1、Session的由來及其實現
HTTP協議是無狀態的協議,同一個客戶端的這次請求和上次請求是沒有對應關系的。也就是說我們無法在服務器端確認兩次請求是否是同一個用戶所為,這為我們在一些應用場景中實現在多次請求間記住用戶狀態帶來麻煩,比如電子商務網站,用戶瀏覽商品、加入購物車、下單、購買需要多個請求才能完成,如果在這些請求之間無法記住用戶狀態,根本無法完成正常的購買行為,為此,引入了Session的概念,其目的就是在請求中記住用戶狀態。
Session的實現機制有兩種,一種是我們通常所見的基於Cookie,即將針對每個用戶生成的唯一Session ID存放在Cookie中,然后用戶每次請求都會帶上這個Session ID,這樣服務器端就能判斷是否是同一個用戶,這種機制需要瀏覽器支持Cookie(現在的瀏覽器默認都支持);另一種是將基於URL重寫,即將Session ID作為參數放到URL中,這樣每次請求也會帶上Session ID,當瀏覽器不支持Cookie時可以使用這種方式。
上述兩種實現機制是針對客戶端的,服務器端也可以將Session存放到不同介質,常見的存儲方式有文件、數據庫、 Memcached 和Redis等。和之前的緩存、隊列一樣,Laravel也為不同的存儲提供了統一的接口,下面我們就來看一下如何在Laravel中實現Session的存儲、訪問、刪除以及更多其它用法。
2、Session配置
Laravel 中 Session 配置文件位於 config/session.php
,默認設置如下:
return [
'driver' => env('SESSION_DRIVER', 'file'), 'lifetime' => 120, 'expire_on_close' => false, 'encrypt' => false, 'files' => storage_path('framework/sessions'), 'connection' => null, 'table' => 'sessions', 'lottery' => [2, 100], 'cookie' => 'laravel_session', 'path' => '/', 'domain' => null, 'secure' => false, ];
driver
配置項用於設置Session存儲方式,默認是 file
,即存儲在文件中,該文件位於 files
配置項配置的路徑,即 storage/framework/sessions
。此外Laravel還支持其它存儲方式:
database
:將Session數據存放到指定數據表中,該數據表由配置項table
設置memcached
:將Session數據存放到Memcached中redis
:將Session數據存放到Redis中array
:將Session數據存放到數組中,該配置僅用於測試環境
要修改 driver
配置,需要去項目根目錄下 .env
文件修改其中的 SESSION_DRIVER
選項。
lifetime
配置項用於設置Session有效期,默認為120分鍾。
expire_on_close
配置項用於設置是否在瀏覽器關閉時立即讓Session失效。
encrypt
配置項用於配置Session數據是否加密。
lottery
配置項用於配置回收Session存放位置。
cookie
配置項用於配置存放Session ID的Cookie名稱,默認是
laravel_session。
path
配置項用於配置存放Session ID的Cookie存放路徑,默認為項目根目錄。
domain
配置項用於配置存放Session ID的Cookie存放域名。
secure
配置項用於配置是否只有在HTTPS協議下發送Session ID到服務器。
使用數據庫存儲Session
需要將 .env
文件中的SESSION_DRIVER修改為 database
,然后將 config/session.php
中 connection
配置修改為 mysql
(如果使用的數據庫是MySQL的話),該配置值對應 config/database.php
中 connections
相應數據庫配置項,也可以使用默認值 null
不做修改。
然后需要在項目根目錄下運行如下Artisan命令:
php artisan session:table composer dump-autoload php artisan migrate
生成存放Session的數據表 sessions
。
使用Memcached/Redis存儲Session
使用Memcached存儲Session只需將 .env
文件中SESSION_DRIVER修改為 memcached
即可。
使用Redis存儲Session需要將 .env
文件中SESSION_DRIVER修改為 redis
,然后將 config/session.php
中 connection
配置修改為 default
(對應 config/database.php
中 redis
主機配置項),當然也可以使用默認值 null
不做修改。
這里我們使用默認配置不做改變(使用文件存儲Session)。
3、Session 使用示例
其實我們之前已經接觸到了Session存儲,比如之前的用戶登錄就會用到,用戶登錄成功之后會將用戶數據存放到Session中。這里我們使用Session存放一些簡單的測試數據。
使用幫助函數session
存放Session可以使用全局幫助函數 session
:
session(['site'=>'LaravelAcademy.org']);
對應Session的訪問方法:
$site = session('site');
此外還支持對Session數組操作:
session(['site.xxx'=>'LaravelAcademy.org']); $site = session('site'); dd($site);
打印結果為:
使用Request實例
以上是快捷存取Session,我們還可以在Request實例上實現對Session更高級的一些操作。
我們可以以這種方式獲取所有Session數據:
$sessions = $request->session()->all();
我們可以像這樣存取Session數據:
$request->session()->put('site', 'http://LaravelAcademy.org'); if($request->session()->has('site')){ $site = $request->session()->get('site'); dd($site); }
此外還可以這樣獲取Session數據(如果對應Session不存在,返回默認值):
$sitename = $request->session()->get('sitename','Laravel學院'); dd($sitename);
此外還可以使用 push
方法推送多個數據到Session數組:
$request->session()->push('site.xxx', 'http://LaravelAcademy.org'); $request->session()->push('site.xxx', 'Laravel學院'); if($request->session()->has('site')){ $site = $request->session()->get('site'); dd($site); }
對應輸出為:
當然我們可以使用如下方式實現異曲同工之效:
$request->session()->put('site.xxx', ['http://LaravelAcademy.org','Laravel學院']);
我們可以使用 pull
方法獲取數據然后將其刪除:
$siteid = $request->session()->pull('siteid','LaravelAcademy'); echo $siteid; $siteid = $request->session()->get('siteid'); echo $siteid;
結果只能打印一個 LaravelAcademy
。
刪除指定Session數據還可以使用 forget
方法:
$request->session()->put('site.name','Laravel學院'); $sitename = session('site.name'); echo $sitename; $request->session()->forget('site.name'); $sitename = session('site.name'); echo $sitename;
結果只能打印一個 Laravel學院
。
還可以通過 flush
方法一次性刪除所有Session數據:
$request->session()->flush();
$sessions = $request->session()->all(); dd($sessions);
打印結果為空數組。
一次性Session數據
所謂一次性數據就是下一次請求中(僅僅是下一次)有效的Session數據,常見的應用場景就是表單驗證錯誤信息。用法也很簡單,使用 flash
方法即可。
比如我們在 TestController@session
中編寫測試代碼如下:
public function session(Request $request){ $request->session()->flash('message', '歡迎訪問Laravel學院!'); }
然后在 TestController@sessionx
中編寫測試代碼如下:
public function sessionx(){ $message = session('message'); echo $message; }
然后在 routes.php
中定義路由規則如下:
Route::get('test/session','TestController@session'); Route::get('test/sessionx','TestController@sessionx');
在瀏覽器中訪問 http://laravel.app:8000/test/session
,然后再訪問 http://laravel.app:8000/test/sessionx
,打印出:
歡迎訪問Laravel學院!
再次刷新 http://laravel.app:8000/test/sessionx
,則頁面顯示空白,說明Session數據已經被銷毀,這就是一次性Session數據。
當然,如果我們想要繼續保持一次性Session數據有效,可以定義 TestController@sessionx
代碼如下:
public function sessionx(Request $request){ $request->session()->reflash(); $message = session('message'); echo $message; }
這樣不管怎么刷新Session數據始終有效。此外還可以指定哪些Session數據有效:
$request->session()->keep(['message']);