HTTP协议是无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系的。也就是说我们无法在服务器端确认两次请求是否是同一个用户所为,这为我们在一些应用场景中实现在多次请求间记住用户状态带来麻烦,比如电子商务网站,用户浏览商品、加入购物车、下单、购买需要多个请求才能完成,如果在这些请求之间无法记住用户状态,根本无法完成正常的购买行为,为此,引入了Session的概念,其目的就是在请求中记住用户状态。
Session的实现机制有两种,一种是我们通常所见的基于Cookie,即将针对每个用户生成的唯一Session ID存放在Cookie中,然后用户每次请求都会带上这个Session ID,这样服务器端就能判断是否是同一个用户,这种机制需要浏览器支持Cookie(现在的浏览器默认都支持);另一种是将基于URL重写,即将Session ID作为参数放到URL中,这样每次请求也会带上Session ID,当浏览器不支持Cookie时可以使用这种方式。
上述两种实现机制是针对客户端的,服务器端也可以将Session存放到不同介质,常见的存储方式有文件、数据库、Memcached和Redis等。和之前的缓存、队列一样,Laravel也为不同的存储提供了统一的接口,下面我们就来看一下如何在Laravel中实现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到服务器。
需要将.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存储Session只需将.env
文件中SESSION_DRIVER修改为memcached
即可。
使用Redis存储Session需要将.env
文件中SESSION_DRIVER修改为redis
,然后将config/session.php
中connection
配置修改为default
(对应config/database.php
中redis
主机配置项),当然也可以使用默认值null
不做修改。
这里我们使用默认配置不做改变(使用文件存储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);
打印结果为:
以上是快捷存取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数据,常见的应用场景就是表单验证错误信息。用法也很简单,使用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']);