根本原因是session.save_path目录权限不足或配置失效,需确认Web进程(如www-data)对该路径有写权限、路径存在且为绝对路径,并检查是否因session.auto_start=1或驱动不匹配导致静默退化。

Session 写不进去,session_id() 总变怎么办
根本不是代码写错了,而是底层存储没生效。最常见的是 Linux 下 session.save_path 目录权限不对——Web 进程(如 www-data)没权限写入。
- 用
php -i | grep session.save_path查真实路径(通常是/var/lib/php/sessions,不是项目里的runtime/session) - 执行
ls -ld /var/lib/php/sessions,确认权限是drwxrwxrwt(末位t表示 sticky bit),否则跑sudo chmod 1733 /var/lib/php/sessions - 别在 ThinkPHP 的
config/session.php里只改type => 'file'却漏配path;若指定自定义路径,必须是绝对路径且 Web 进程可写 - 检查 php-fpm 的
www.conf是否开了session.auto_start = 1,开了就会和 ThinkPHP 的SessionInit冲突,导致session_start()被调两次,静默失败
Session::get('lang') 返回空,但语言切换链接明明点了
不是 Session 没存,是语言初始化太早——Lang::load() 在 Session::get('lang') 之前就执行了,读到的永远是默认语言。
- 确保中间件顺序:
SessionInit必须在语言加载中间件之前执行;在app/middleware.php里把think\middleware\SessionInit::class放到最前 - 别在全局配置或行为里提前调
Lang::load();所有语言包加载逻辑必须放在 Session 可读之后,比如控制器基类的initialize()方法里 - 确认
config/session.php中auto_start为true,否则Session::get()在生命周期早期会返回空 - 多应用模式下,检查各应用的
middleware.php是否各自独立配置了 Session 初始化
跨域请求时 Session 丢失,credentials: 'include' 也设了还是没用
前端带了凭证,后端却没接住——问题出在 Cookie 域名、响应头或驱动配置三处。
- 后端响应头必须同时满足:
Access-Control-Allow-Origin不能是*,得写具体域名(如https://admin.example.com);Access-Control-Allow-Credentials必须为true - Cookie 的
domain要设对:主站example.com,API 是api.example.com,则config/session.php中的domain应设为.example.com(开头带点) - Redis 驱动下,如果
host或port配错,ThinkPHP 会静默 fallback 到内存存储,请求一结束 Session 就丢;用redis-cli -h 127.0.0.1 ping确保服务可达 - HTTPS 环境下,务必设
secure => true,否则浏览器拒绝发送 Cookie
登出后语言还保留,Session::clear() 为什么不管用
Session::clear() 清空全部键,但语言标识可能被其他逻辑覆盖或未触发重载;更麻烦的是,它可能误删购物车等非登录相关数据。
立即学习“PHP免费学习笔记(深入)”;
- 登出时不要用
Session::clear(),而应精准删除:Session::delete('user_id')+Session::delete('lang') - 语言切换接口本身不该清 Session,只写
Session::set('lang', $lang);登出逻辑才是唯一该删lang的地方 - 如果用了 Token + Session 混合方案,登出必须同步清理:
Cache::pull('token_' . $uid)+Session::delete('user_id')+Session::delete('lang'),缺一不可 - 注意中间件执行顺序:登出接口的中间件必须在 Session 销毁前读取并记录
lang值,否则删完再读就是空



















