2015-11-24 20:26:32 5659次浏览 2条回答 0 悬赏 10 金钱

正常情况下addFlash()添加的内容会在getFlash()之后被销毁,然而这两天在将 YII_ENV 参数配置为 prod(web/index.php : defined('YII_ENV') or define('YII_ENV', 'prod');) 之后发现自动销毁失效,添加的内容会一直存在,后来逐步检查,进一步发现是问题出在config/web.php:

if (YII_ENV_DEV) {
    // configuration adjustments for 'dev' environment
    $config['bootstrap'][] = 'debug';
    $config['modules']['debug'] = 'yii\debug\Module';
    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => 'yii\gii\Module',
        #'password' => 'gii',
        'allowedIPs' => ['127.0.0.1', '10.0.0.*', '*.*.*.*'] // 按需调整这里
    ];
}

prod模式下没有加载debug模块,在手动加载debug模块之后,flash的销毁恢复正常。
即 启用这两行代码:

$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';

找了半天没发现debug module 和 flsah,session之间有什么关系,不理解,不科学,故求助各位~~

最佳答案

  • 500miles 发布于 2015-11-25 09:50 举报

    flash内容存储在session中, 和debug module没什么关系.

    addFlash('a', 'b') 之后, 再getFlash('a')之后, 是可以销毁这条消息.

    但是 : 是在下次请求中销毁, 本次请求的后续处理中还存在.

    11 条回复
    回复于 2015-11-25 10:07 回复

    这个我是知道的,补充一下,是在不加载debug module的情况下。getFlash()且非同一次请求,没有销毁这条信息,
    即使是在getFlash()中将参数delete显示置为true也没用。

    回复于 2015-11-25 11:54 回复

    @sabersma

    那真是有点奇怪 . 我机器上试了几次, 加不加载 debug 都正常 .
    
    又仔细看了代码. debug 模块是有操作 flash, 但仅限于获取值 (不同于 getFlash 修改生存周期) 
    
    其他也没发现有什么会影响到了.  所以我觉得可以排除 debug 模块的影响.  
    
    
    显式设定 deletetrue 也不行  猜测问题直指 session 模块了
    
    有其他信息可以提供的话 可以一起探讨猜测一下
    
    
    回复于 2015-11-25 17:10 回复


    额,不好意思我记错了,getFlash()时置delete=true 或是调用$session->removeFlash()都是有效的。但是除此之外的自动销毁还是无效。刚才写了下测试:
    actions:

    public function actionTestFlash() {
        Yii::$app->session->setFlash('delete when access', 'hello world', true);
        Yii::$app->session->setFlash('delete when next call', 'hello world', false);
        Yii::$app->session->setFlash('set delete when getFlash', 'hello world');
        Yii::$app->session->setFlash('set nothing, wait for auto delete in the next call', 'hello world');
    }
    
    public function actionNewCall1() {
        return $this->render('new_call1');
    }
    
    public function actionNewCall2() {
        return $this->render('new_call2');
    }
    

    new_call1.php:

    $session = Yii::$app->session;
    var_dump('delete when access' . ' - ' . $session->getFlash('delete when access'));
    var_dump('delete when next call' . ' - ' . $session->getFlash('delete when next call'));
    var_dump('set delete when getFlash' . ' - ' . $session->getFlash('set delete when getFlash', null, true));
    var_dump('set nothing, wait for auto delete in the next call' . ' - ' . $session->getFlash('set nothing, wait for auto delete in the next call'));
    var_dump($_SESSION);
    

    new_call2.php:

    $session = Yii::$app->session;
    $flashes = $session->getAllFlashes();
    
    var_dump($flashes);
    var_dump($_SESSION);
    $session->removeAllFlashes();
    

    new-call1的输出:

    string(32) "delete when access - hello world"
    string(35) "delete when next call - hello world"
    string(38) "set delete when getFlash - hello world"
    string(64) "set nothing, wait for auto delete in the next call - hello world"
    array(4) {
      ["delete when access"]=>
      string(11) "hello world"
      ["__flash"]=>
      array(3) {
        ["delete when access"]=>
        int(1)
        ["delete when next call"]=>
        int(0)
        ["set nothing, wait for auto delete in the next call"]=>
        int(1)
      }
      ["delete when next call"]=>
      string(11) "hello world"
      ["set nothing, wait for auto delete in the next call"]=>
      string(11) "hello world"
    }
    

    new_call2输出:

    array(3) {
      ["delete when access"]=>
      string(11) "hello world"
      ["delete when next call"]=>
      string(11) "hello world"
      ["set nothing, wait for auto delete in the next call"]=>
      string(11) "hello world"
    }
    array(4) {
      ["delete when access"]=>
      string(11) "hello world"
      ["__flash"]=>
      array(3) {
        ["delete when access"]=>
        int(1)
        ["delete when next call"]=>
        int(0)
        ["set nothing, wait for auto delete in the next call"]=>
        int(1)
      }
      ["delete when next call"]=>
      string(11) "hello world"
      ["set nothing, wait for auto delete in the next call"]=>
      string(11) "hello world"
    }
    

    除了在getFlash()时设置delete=true的那次之外其余三次均没有正常销毁,当然,removeAllFlashes()之后整个世界都清净了。

    回复于 2015-11-25 17:11 回复

    额,输出部分格式贴乱了,,凑合着看吧

    回复于 2015-11-25 17:18 回复

    其实也就是setFlash()参数$removeAfterAccess = true (delete after access) or false (delete until the next call) 两种情况下的自动销毁没有生效,但是其他方式的显式删除flash是可以的。(第四个case == 第一个case, 忽略它吧)

    是别的地方有什么需要配置吗?

    回复于 2015-11-25 18:21 回复

    显式指定 delete 可以删除成功, 说明session并没有问题.... 那原因出在哪里了.. yii\web\Session 里面有个 updateFlashCounters 方法 每次请求都会执行一次 清理过期flash 你不会是动过这个地方的源码吧 composer status 执行一下 看源码有无改动

    回复于 2015-11-25 18:22 回复

    并不需要其他什么配置 完全依赖session的 真是有点奇怪

    回复于 2015-11-25 18:40 回复

    没有用composer装,刚才看了一下本地的源码和git上的源码,一致的,在源码里加了测试code,看起来,updateFlashCounters() 没有被调用。。。

    回复于 2015-11-25 19:24 回复

    大概找到原因了。。推测是因为Yii入口脚本我使用session_start()开启session而不是使用Yii::$app->session->open()方式开启,

    public function open()
    {
        if ($this->getIsActive()) {
            return;
        }
        $this->registerSessionHandler();
        $this->setCookieParamsInternal();
        @session_start();
        if ($this->getIsActive()) {
            Yii::info('Session started', __METHOD__);
            $this->updateFlashCounters();
        } else {
            $error = error_get_last();
            $message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
            Yii::error($message, __METHOD__);
        }
    }
    

    所以导致open()在调用时,判断到session已开启直接返回,没有执行后续的updateFlashCounters()方法进行清理,感觉这里的代码,,嗯。有点不太。。机智?

    回复于 2015-11-26 10:13 回复

    最佳实践肯定是不要直接操作 $_SESSION $_COOKIE $_GET ... 这些, 不安全 并且容易引起紊乱 . 不过这个地方也确实是个小坑儿, 引起的bug不易察觉啊 ... 看了下 官方issues里面也有在争论这个地方, 下个版本可能会改进吧.

    回复于 2015-11-26 10:15 回复

    另外 把这个问题标记为 已解决 吧

    觉得很赞
  • 回答于 2018-01-23 11:37 举报

    在vendor\yiisoft\yii2\web\Session.php中是有两处调用$this->updateFlashCounters();的,我在慕课网看的yii电商教程老师给的代码少了一行,就导致getFlash一直能够获取值

您需要登录后才可以回答。登录 | 立即注册
sabersma
职场新人

sabersma

注册时间:2015-11-24
最后登录:2017-10-11
在线时长:1小时8分
  • 粉丝0
  • 金钱85
  • 威望0
  • 积分95

热门问题