zoukankan      html  css  js  c++  java
  • Laravel Session 遇到的坑

    这两天遇到了一个很奇怪的问题,更新sessionsession的值不变。经过一番追查,终于找到问题,并搞明白了原理。写这篇博客记录下。

    框架版本

    Laravel 5.4

    问题

    先来描述下问题,我在我们项目基础的Middleware中,加入session操作,存入了一个值,再在Controller中取出使用,大致代码如下:

    // Middleware
    public function handle($request, Closure $next)
    {
        $id = Redis::get('id');
        session(['id' => $id]);
        return $next($request);
    }
    
    // Controller
    public function index()
    {
        $id = session('id');
        return ['id' => $id];
    }
    

    假设reids中的id是1,这一次访问index这个action,返回的是1,当你将redisid的值改成2时,在访问,发现返回的还是1,而且之后的访问也都是1。这里说明一下session使用的是redis

    解决问题

    看到这样神奇的结果,百思不得其解。于是打开Xdebug,开始调试。经过多次调试,发现在执行完
    IlluminateSessionMiddlewareStartSession这个Middleware后,session里面的值就变回1了,在之前都是2。然后想到会不会我们的MiddlewareStartSession之前执行造成的,将我们的Middleware移到StartSession之后,发现果然可以了,app/Http/Kernel.php中的代码如下:

    protected $middlewareGroups = [
        'web' => [
            IlluminateCookieMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            IlluminateRoutingMiddlewareSubstituteBindings::class,
            AppHttpMiddlewareOurMiddleware::class,
        ]
    ];
    

    其中的OurMiddleware是我们自己写的Middleware,之前是放在最上面的,$next($request)之前的代码的执行顺序是从上到下的,如果OurMiddleware中有些内容是必须在最开始的,可以考虑分成两个Middleware

    理解原理

    虽然解决了问题,但还是不知道其原理究竟是怎样的,带着这样的疑问我继续查看源码,最终找到了相应的内容。

    • session不是实时落地的,也就是说当你调用session(['id' => $id])时,id并没有被真正存入redis中,而是缓存在 IlluminateSessionStore单例的attributes属性中,可以查看其put方法,代码如下:

    public function put($key, $value = null)
    {
    if (! is_array($key)) {
    $key = [$key => $value];
    }

        foreach ($key as $arrayKey => $arrayValue) {
            Arr::set($this->attributes, $arrayKey, $arrayValue);
        }
    

    }
    ```

    • IlluminateSessionMiddlewareStartSession在执行时,回自动加载redis中已经实例化的数据,并覆盖IlluminateSessionStore单例中的attributes属性,所以这就导致我们一直取到的都是redis中的session数据。加载覆盖的代码如下:

    protected function loadSession()
    {
    $this->attributes = array_merge($this->attributes, $this->readFromHandler());
    }
    protected function readFromHandler()
    {
    if ($data = $this->handler->read($this->getId())) {
    $data = @unserialize($this->prepareForUnserialize($data));

            if ($data !== false && ! is_null($data) && is_array($data)) {
                return $data;
            }
        }
    
        return [];
    

    }
    ```

    其中的readFromHandler方法就是获取redis中的session数据。

    后记

    其实这不是Laravel session的坑,是我自己踩坑,原谅我是个标题党

  • 相关阅读:
    朴素贝叶斯分类-实战篇-如何进行文本分类
    朴素贝叶斯分类-理论篇-如何通过概率解决分类问题
    数据变换-归一化与标准化
    你还不懂傅里叶变换,那就过来掐死我吧
    Python快速入门 ---- 系列文章
    批处理中的时间计算详解
    使用electron+vue开发一个跨平台todolist(便签)桌面应用
    文科妹子都会用 GitHub,你这个工科生还等什么
    如约而至,.NET 5.0 正式发布
    如何进行正确的沟通?
  • 原文地址:https://www.cnblogs.com/CraryPrimitiveMan/p/6654674.html
Copyright © 2011-2022 走看看