webman默认文件存储session,多进程下各worker独立读写本地文件导致数据不一致;必须改用redis等共享后端,并正确配置handler、redis连接参数及cookie域与安全属性。

Webman 的 Session 默认是文件存储,多进程下必然失效;必须显式切换为 Redis 或数据库等共享后端,否则无论怎么调用 session_start() 或 $request->session() 都无法跨 Worker 保持状态。
为什么 $request->session() 看似能用却总丢数据
这是最典型的误判场景:代码里写了 $request->session()->set('user_id', 123),也能读出来,但换一个请求或重启 Worker 后就没了。根本原因不是写法错,而是底层仍走 PHP 默认的 files handler,每个 Worker 进程各自读写自己本地的 session 文件,互相不可见。
- Webman 的
$request->session()只是封装,不改变存储引擎;它默认仍依赖session.save_handler=files和session.save_path指向的目录 -
runtime/session/目录权限不足(如 www-data 不可写)会导致静默失败,$_SESSION看似有值,实则根本没存进去 - 未禁用 PHP 原生 Session 自动启动(
session.auto_start=1)时,可能与 Webman 的手动初始化冲突,造成 ID 不一致
切换 Redis 存储只需改三处配置
不用重写逻辑,也不用动中间件,直接在 config/session.php 中调整即可生效:
- 把
'handler' => \support\session\File::class改成'handler' => \support\session\Redis::class - 确保
'redis' => ['host' => '127.0.0.1', 'port' => 6379, 'database' => 0]可连通;若 Redis 有密码,必须加'auth' => 'your_password' -
'prefix' => 'session:'建议显式设置,避免和其他业务 key 冲突;不要留空或用默认空字符串
注意:session.save_path 在 Webman 中**不生效**,所有连接参数必须通过 redis 数组传入;设了也白设。
Cookie 域和安全配置不匹配会导致前端根本发不出 PHPSESSID
即使 Redis 存好了,浏览器不带 Cookie,服务端也拿不到 session_id —— 这类问题常被当成“Session 没保存”,其实是传输层断了。
- 跨子域(如
a.example.com↔b.example.com)必须设'cookie_domain' => '.example.com',开头那个点号.不能漏 - HTTPS 站点必须设
'secure' => true,否则浏览器拒绝发送带Secure标志的 Cookie;HTTP 环境下必须为false,否则 Cookie 彻底消失 -
'httponly' => true和'samesite' => 'Lax'是默认推荐值;若需 iframe 跨站嵌入,才考虑'samesite' => 'None',但此时secure必须为true
手动生成并复用 session_id 容易踩的坑
有些场景(如 API 登录后跳转、SSO 接入)需要主动控制 session_id,这时不能只靠 session_start(),得显式接管:
- 用
session_id($id)设置 ID 后,**必须紧接着调用session_start()**,否则后续$request->session()仍会生成新 ID - 不要在
$request->session()返回对象后,再用session_id()改 ID —— 此时 session 已按旧 ID 加载,改了也白改 - 如果把
$session对象赋给全局变量(如$GLOBALS['sess'] = $request->session()),PHP GC 不会销毁它,save()不会自动触发,必须手动调用$session->save()
真正关键的不是“怎么存”,而是“谁在什么时候决定用哪个 ID”——这个决策点一旦错位,后面所有操作都是在错误上下文中进行。











