Session::set()在中间件中静默失败,必须确保SessionInit中间件排在自定义中间件之前;推荐使用$request->session()->set()替代Session::set()以保证可靠性。

中间件里调用 Session::set() 会静默失败
不能直接操作,除非中间件执行顺序在 SessionInit 之后。TP6 的 Session 底层依赖 Store 实例,而该实例由 SessionInit 中间件初始化。如果自定义中间件排在它前面(默认全局中间件数组顺序靠前),Session::set() 看似执行成功,但数据根本不会写入,下个请求也读不到。
常见错误现象:
-
Session::set('test', 'ok')后Session::get('test')返回null - 控制器里能读到 Session,但中间件里设的值始终丢失
- 没报错、没警告,就是“没生效”——这是最典型的未初始化表现
必须确保 SessionInit 在自定义中间件之前注册
打开 app/middleware.php,检查数组顺序。正确的写法是:
return [
\think\middleware\SessionInit::class,
\app\middleware\CheckAuth::class,
// 其他中间件...
];
如果你用的是多应用模式(如 app/admin),要确认修改的是对应应用下的 middleware.php,而不是全局文件。
立即学习“PHP免费学习笔记(深入)”;
验证是否生效的方法:
- 在中间件
handle()方法里写session('debug', 'in-mw');+var_dump(session('debug')); - 访问接口,输出
string(6) "in-mw"才算真正可用 - 别用
$_SESSION判断——它在 TP6 里永远为空
中间件中 Session 操作的边界要注意
Session 数据是在整个请求生命周期结束时统一写入的,所以中间件里设的值,控制器和视图都能读到;但有几点容易踩坑:
- 中间件里调用
Session::pull('key'),后续控制器再get()就是null—— 因为 pull 是“取完即删” - 不要在中间件里
exit或抛出未捕获异常,否则 Session 写入会被跳过 - 闪存(
flash())在中间件里设了,下个请求才生效,但若中间件链里有重定向,需确认目标请求仍走完整中间件流程 - 文件驱动下,
runtime/session目录权限不足会导致写入失败,此时set()也不报错,只静默丢弃
替代方案:用 Request::session() 更明确
虽然 Session::set() 和 session() 助手函数都可用,但在中间件里推荐显式使用 $request->session(),语义更清晰,且避免门面类可能的延迟加载问题:
public function handle($request, \Closure $next)
{
$request->session()->set('from_mw', true);
return $next($request);
}
注意:$request->session() 返回的是 think\Session 实例,方法名和 Session:: 一致(如 set()、get()、has()),但底层绑定的是当前已初始化的 Store,可靠性更高。
真正容易被忽略的点是:Session 初始化不是“配置了就自动生效”,而是强依赖中间件注册顺序和执行时机。哪怕你把 SessionInit 加进去了,排错时第一反应也该是查数组位置,而不是怀疑代码逻辑。



















