文档章节

Laravel5.3之Session源码解析(下)

botkenni
 botkenni
发布于 2016/11/19 10:32
字数 1017
阅读 68
收藏 1

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

开发环境:Laravel5.3 + PHP7

关闭Session

首先看下\Illuminate\Session\Middleware\StartSession::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,先看第一件事:

    // \Illuminate\Session\Middleware\StartSession
    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']);
    }

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

(1) $session->getName()

// $session就是\Illuminate\Session\Store对象

// 在实例化Store对象时,传入的name值是读取的app['config']['session.cookie']
// 见 \Illuminate\Session\SessionManager::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的三大步。后续有好的技术再分享吧,到时见。

 

© 著作权归作者所有

共有 人打赏支持
botkenni
粉丝 17
博文 405
码字总数 433796
作品 0
西城
程序员
私信 提问
Laravel5.3之Session源码解析(上)

说明:本文主要通过学习Laravel的session源码学习Laravel是如何设计session的,将自己的学习心得分享出来,希望对别人有所帮助。Laravel在中定义了session中间件,并通过该中间件来设计sessi...

botkenni
2016/11/18
13
0
Laravel5.3之Session源码解析(中)

说明:在上篇中学习了session的启动过程,主要分为两步,一是session的实例化,即IlluminateSessionStore的实例化;二是从session存储介质redis中读取的数据。Laravel5.3把session垃圾回收放...

botkenni
2016/11/19
12
0
Laravel5.3之Container源码解析

说明:本文主要学习Laravel中Container的源码,主要学习Container的绑定和解析过程,和解析过程中的依赖解决。分享自己的研究心得,希望对别人有所帮助。实际上Container的绑定主要有三种方式...

botkenni
2016/10/28
16
0
Laravel5.3之Middleware源码解析

说明:本文主要学习Laravel的Middleware的源码设计思想,并将学习心得分享出来,希望对别人有所帮助。Laravel5.3之Decorator Pattern已经聊过Laravel使用了Decorator Pattern来设计Middlewar...

botkenni
2016/10/27
37
0
Laravel5.3之bootstrap源码解析

说明:Laravel在把Request通过送入中间件Middleware和路由Router之前,还做了程序的启动Bootstrap工作,本文主要学习相关源码,看看Laravel启动程序做了哪些具体工作,并将个人的研究心得分享...

botkenni
2016/10/28
363
0

没有更多内容

加载失败,请刷新页面

加载更多

docker搞个wordpress

1.先把wordpress的镜像下载下来 docker pull wordpress 2.下载mysql docker pull mysql:lastest 3.启动mysql docker run --name blog -e root -d mysql:5.7 docker run --name some-mysql -e......

无极之岚
2分钟前
0
0
【宇润日常疯测-005】PHP 中的 clone 和 new 性能比较

clone和new本不应该放在一起比较,它们的作用是不同的。但可能有一些场景下,可以用clone也可以用new,那么这时候我们选哪个呢? 我编写了两个测试,第一个是声明一个空类,第二个是带构造方...

宇润
2分钟前
0
0
点击按钮弹出类似IOS 底部 dialog

implementation 'com.baoyz.actionsheet:library:1.1.7' 然后设置按钮点击监听,,调用下列代码即可 ActionSheet.createBuilder(this, getSupportFragmentManager()) ......

lanyu96
5分钟前
0
0
专访阿里云专有云马劲,一个理性的理想主义者

“我的故事都是和团队技术相关的,自己还真没有什么引人入胜的故事。”当马劲被问到能不能多分享些个人经历故事时他笑着说,我们就干脆怀着好奇聊了聊他和阿里云专有云一路走来的故事。 马劲...

阿里云官方博客
37分钟前
1
0
java环形缓冲区

import java.util.ArrayList;import java.util.List;/** * * 环形缓冲区<br/> * 一. 写数据:<br/> * 1. push: 当数据已写满时返回false,否则可以正常写入返回true<br/>......

whoisliang
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部