Laravel Session 问题核心在于驱动匹配环境:array驱动仅测试用、cookie超4KB或HTTPS未设secure致失效;Redis驱动需正确配置连接与扩展;regenerate()防会话固定,migrate()仅换ID;自定义驱动须规范实现read/write/gc且注入ConnectionInterface。

Session 在 Laravel 中默认可用,但实际项目中常因配置不当、驱动误选或生命周期理解偏差导致数据存不住、跨请求丢失、测试环境失效等问题。核心判断标准只有一条:你用的驱动是否匹配当前部署环境与需求。
为什么 session()->put() 存了却读不到?
最常见原因是会话未启动或驱动不支持当前上下文:
-
php artisan serve启动时若未启用session_start()(Laravel 通常自动处理,但中间件顺序错乱可能跳过) - 使用
array驱动(默认仅用于测试)——它不持久化,每次请求都是新数组 - 使用
cookie驱动但数据超 4KB,浏览器截断导致解密失败,session()->get()返回null - HTTPS 环境下未设置
'secure' => true,而 Cookie 被浏览器拒绝发送
验证方式:在路由闭包中加
dd(session()->getId(), session()->isStarted());,若 ID 为空或
isStarted() 为 false,说明会话根本没激活。
如何安全切换到 redis 驱动并避免连接失败?
Redis 是生产推荐驱动,但配置疏漏会导致整个应用 500 错误:
- 确保
config/session.php中'driver' => 'redis',且'connection'值与config/database.php的redis.default名称一致 - 必须安装
predis/predis或phpredis扩展;Laravel 10+ 默认用phpredis,若未启用扩展会静默回退到file驱动(日志里无报错但行为异常) - Redis 连接超时默认 5 秒,高并发下建议调低:
'options' => [ 'connection_timeout' => 1, 'read_write_timeout' => 1, ] - Session key 默认前缀是
laravel_session:,如需隔离多应用,请改'prefix'配置项,避免键冲突
session()->regenerate() 和 session()->migrate() 该用哪个?
二者都重置 Session ID,但语义和适用场景不同:
-
session()->regenerate():销毁旧 session 数据,生成新 ID,适用于登录成功后防会话固定(Session Fixation)。它会保留当前已put()的数据 -
session()->migrate():仅更换 ID,不销毁原数据,旧 ID 对应的数据仍可被读取(直到过期),安全性弱于regenerate() - 重要细节:两者都要求会话已启动;若在中间件中调用,需确保执行时机在
StartSession之后,否则无效
典型登录后操作:
Auth::login($user); session()->regenerate(true); // true 表示删除旧 session 文件(对 file/redis 驱动有效)
自定义 Session 驱动时最容易被忽略的点
实现 SessionHandlerInterface 不难,但以下三点不处理就会“存得进、取不出”:
-
read($id)必须返回字符串,哪怕空也要返回'',返回null或false会被 Laravel 当作“会话不存在”,直接新建一个 -
write($id, $data)中的$data是 PHP 序列化后的字符串(含 | 分隔符),不要二次serialize(),否则解码失败 - 务必实现
gc($maxLifetime),否则自定义驱动不会触发垃圾回收,过期 session 永远堆积
另外,Laravel 9+ 强制要求自定义驱动类注册时传入 ConnectionInterface 实例(如数据库连接),不能直接 new PDO —— 否则无法参与连接池和事务上下文。











