CodeIgniter 4会话需手动重置生命周期:登录后必须调用$this->session->regenerate(TRUE);前端心跳+后端set()更新last_activity;数据库驱动下应调整sess_time_to_update和sess_gc_probability以优化性能。

会话过期时间设置不等于自动刷新
很多人误以为只要把 sess_expiration 设得长(比如 86400 秒),用户就能一直不掉线。实际不是:CodeIgniter 4 的会话默认是「静默过期」的,即从创建那一刻起倒计时,不管用户有没有操作。用户在页面上点十次按钮,只要总耗时超过设定值,下次请求仍会触发会话销毁。
真正需要的是「用户有操作就重置过期时间」,这靠框架默认行为做不到,必须手动干预。
登录后必须调用 $this->session->regenerate()
这是防止会话固定攻击的强制步骤,但顺便也重置了会话的生命周期起点。如果不做这一步,旧会话 ID 仍在使用,后续所有刷新逻辑都可能失效。
- 务必在登录成功验证后立即执行:
$this->session->regenerate(TRUE)(TRUE表示删除旧会话数据) - 不要在构造函数里调用 —— 构造函数无法访问完整会话上下文,容易报错
- 如果用了自定义会话驱动(如数据库),确保
sess_match_ip和sess_match_useragent没被意外开启,否则 regenerate 可能失败并静默丢弃会话
前端心跳 + 后端更新 last_activity 是最稳方案
CodeIgniter 4 自带的 last_activity 字段只在每次请求时由框架自动更新,但前提是该请求触发了会话读写。AJAX 请求若没显式访问 $this->session,这个时间戳就不会动 —— 导致看似活跃的用户被误判为离线。
所以可靠做法是:前端定时发轻量心跳,后端强制更新会话元数据。
- 前端加一段
setInterval(() => fetch('/api/heartbeat', { method: 'POST' }), 60000) - 后端路由绑定到一个空控制器方法,里面只写一行:
$this->session->set('heartbeat', time())(哪怕只是设个无意义键,也能触发框架更新last_activity) - 别依赖
session_write_close()手动刷盘 —— CodeIgniter 4 在响应结束时自动处理,提前调用反而可能中断后续逻辑
注意数据库会话驱动下的垃圾回收陷阱
如果你用的是 database 会话驱动(推荐用于生产环境),sess_expiration 不仅控制单个会话寿命,还影响 GC(垃圾回收)频率。GC 默认每 500 次请求执行一次,清理过期记录;但如果并发高、心跳密集,GC 可能跟不上,导致 ci_sessions 表膨胀,查询变慢,间接拖垮会话读取性能。
建议同步调整两项配置:
-
sess_time_to_update设为300(5 分钟):避免每次心跳都写库,降低 DB 压力 -
sess_gc_probability设为1(而非默认5):提高 GC 触发频率,配合心跳节奏清理
这个组合不会让会话“永远不掉线”,但能让掉线时机更贴近真实用户行为 —— 而不是卡在某个静态页面 20 分钟后突然 403。


















