說明:在中篇中學習了session的CRUD增刪改查操做,本篇主要學習關閉session的相關源碼。實際上,在Laravel5.3中關閉session主要包括兩個過程:保存當前URL到session介質中;在Response Header中存入cookie。其中,Laravel5.3把垃圾回收提早到了中間件的前置操做,中篇有聊到。OK,學習下關閉session的源碼吧先。php
開發環境:Laravel5.3 + PHP7
laravel
首先看下\Illuminate\Session\Middleware\StartSession::class
中間件源碼的handle()方法:ajax
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。redis
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,看下第二件事:markdown
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所須要的各個參數值爲:cookie
(1) $session->getName()session
// $session就是\Illuminate\Session\Store對象
// 在實例化Store對象時,傳入的name值是讀取的app['config']['session.cookie'] // 見 \Illuminate\Session\SessionManager::buildSession() line 178 'laravel_session' = $session->getName();
(2) $session->getId()app
// 在實例化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()dom
// 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的三大步。後續有好的技術再分享吧,到時見。