• Laravel学习笔记之Session源码解析(下)


    说明:在中篇中学习了session的CRUD增删改查操作,本篇主要学习关闭session的相关源码。实际上,在Laravel5.3中关闭session主要包括两个过程:保存当前URL到session介质中;在Response Header中存入cookie。其中,Laravel5.3把垃圾回收提前到了中间件的前置操作,中篇有聊到。OK,学习下关闭session的源码吧先。

    开发环境:Laravel5.3 + PHP7

    关闭Session

    首先看下IlluminateSessionMiddlewareStartSession::class中间件源码的handle()方法:

        public function handle($request, Closure $next)
        {
            ...
        
            $response = $next($request);
    
            // 检查config/session.php中'driver'是否设置,这里已经假设是redis作为存储介质
            if ($this->sessionConfigured()) {
                // 存储当前URL
                $this->storeCurrentUrl($request, $session);
                // 往Response Header中添加cookie
                $this->addCookieToResponse($response, $session);
            }
    
            return $response;
        }
        
        protected function sessionConfigured()
        {
            return ! is_null(Arr::get($this->manager->getSessionConfig(), 'driver'));
        }

    从源码中可知关闭session做了两件事:存储当前URL;往Response Header中添加cookie。

    OK,先看第一件事:

        // IlluminateSessionMiddlewareStartSession
        protected function storeCurrentUrl(Request $request, $session)
        {
            // 如果是GET,并且不是ajax,且route对象不能为空
            if ($request->method() === 'GET' && $request->route() && ! $request->ajax()) {
                $session->setPreviousUrl($request->fullUrl());
            }
        }
        
        public function setPreviousUrl($url)
        {
            // 使用中篇聊到的put()方法更新式存储$url,
            // 如sentry.app:8888/session,存入到redis中的'laravel:_previous.url'
            $this->put('_previous.url', $url);
        }

    所以第一件事很简单,OK,看下第二件事:

        protected function addCookieToResponse(Response $response, SessionInterface $session)
        {
            // No, we use redis as a session handler.
            if ($this->usingCookieSessions()) {
                $this->manager->driver()->save();
            }
    
            // Yes, use redis as the persistent store bucket.
            if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) {
                $response->headers->setCookie(new Cookie(
                    // 'laravel_session'
                    $session->getName(),
                    // Str::random(40)
                    $session->getId(),
                    // If it is not set to expire when the browser close. And after 60 minutes, the session will close.
                    $this->getCookieExpirationDate(),
                    // '/session'
                    $config['path'],
                    // 'session_domain'
                    $config['domain'],
                    // true
                    Arr::get($config, 'secure', false),
                    // true
                    Arr::get($config, 'http_only', true)
                ));
            }
        }
        
        // 检查是不是cookie存储作为handler,这里是使用redis作为handler
        protected function usingCookieSessions()
        {
            if (! $this->sessionConfigured()) {
                return false;
            }
    
            return $this->manager->driver()->getHandler() instanceof CookieSessionHandler;
        }
        
        // 检查是不是永久存储,array不是永久存储,这里使用redis是永久存储
        protected function sessionIsPersistent(array $config = null)
        {
            $config = $config ?: $this->manager->getSessionConfig();
    
            return ! in_array($config['driver'], [null, 'array']);
        }

    第二件事也很简单,实例化SymfonyComponentHttpFoundationCookie,并存入到response header中。其中,实例化Cookie所需要的各个参数值为:

    (1) $session->getName()

    // $session就是IlluminateSessionStore对象
    
    // 在实例化Store对象时,传入的name值是读取的app['config']['session.cookie']
    // 见 IlluminateSessionSessionManager::buildSession() line 178
    'laravel_session' = $session->getName(); 
    
    
    

    (2) $session->getId()

    // 在实例化Store时,传入的$id=null,则在Store构造函数中使用setId()设置$id值
    //看下Store::setId()源码就知道id是随机生成的长度为40的字符串
    Str::random(40) = $session->getId();
    
        public function setId($id)
        {
            if (! $this->isValidId($id)) {
                $id = $this->generateSessionId();
            }
    
            $this->id = $id;
        }
        public function isValidId($id)
        {
            return is_string($id) && ctype_alnum($id) && strlen($id) === 40;
        }
        protected function generateSessionId()
        {
            return Str::random(40);
        }

    (3) $this->getCookieExpirationDate()

        // config/session.php中默认expire_on_close = false, lifetime = 60
        // 表示如果浏览器关闭session不过期,则保留60分钟后再过期
        protected function getCookieExpirationDate()
        {
            $config = $this->manager->getSessionConfig();
    
            return $config['expire_on_close'] ? 0 : Carbon::now()->addMinutes($config['lifetime']);
        }

    (4) $config['path']

    // 默认是'/',这是设置'/session',等会看下响应头
    '/session' = $config['path']

    (5) $config['domain']

    // 这里在config/session.php中设置成'session_domain',等会看下响应头
    'session_domain' = $config['domain']

    (6) Arr::get($config, 'secure', false)

    // 就默认值false
    false = Arr::get($config, 'secure', false)

    (7) Arr::get($config, 'http_only', true)

    // 就默认值true
    true = Arr::get($config, 'http_only', true)

    这里输入路由sentry.app:8888/session(在本地环境配置你的路由)简单输出个字符串'session',主要看下响应头是不是设置了配置的cookie值:

    看下响应头设置了'laravel_session' cookie,并且'path','domain'是刚刚在session.php中设置的'/session','session_domain'值。总之,Laravel关闭session的第二件事就是给Response Header添加'laravel_session' cookie。

    通过对Laravel Session的源码分析可看出Session共分为三大步:启动Session;操作Session;关闭Session。启动Session包括Store实例化,从存储介质中如redis读取session数据,和垃圾回收;操作Session包括对Session的CRUD增删改查操作;关闭Session包括存储当前的URL和往Response Header添加Cookie。

    总结:本小系列主要学习了Laravel Session的源码,学习了Session的三大步。后续有好的技术再分享吧,到时见。

  • 相关阅读:
    js-AOP
    jQueryUI之autocomplete
    nginx安装配置
    oracle结构语法
    ajax/表单提交 多个相同name的处理方法
    ES6模块化
    docker运维
    帆软报表
    oracle锁表
    香港到大陆IPLC节点故障
  • 原文地址:https://www.cnblogs.com/grimm/p/8462322.html
Copyright © 2020-2023  润新知