后台系统里填了半天表单,点保存弹出「登录已过期,请重新登录」,内容全丢了。用户骂系统难用,开发这边也烦:到底什么时候算过期,怎么才能既安全又不折腾人。

session 到底是什么

用户登录成功后,服务端生成一个 session 对象存在内存或者 Redis 里,同时给浏览器一个 session id(通常在 Cookie 里)。之后每个请求带上这个 id,服务端就能认出是谁。过期指的是服务端把这条记录删了,或者标记为失效,浏览器再带着 id 过来就找不到对应的人。

过期由谁决定

  • 闲置超时:一段时间没有任何操作就失效,PHP 默认是 1440 秒,24 分钟。
  • 绝对超时:从登录那一刻算起,不管有没有操作,到点就失效,比如 12 小时。
  • 服务端重启:session 存在本机内存里的,进程一重启全丢,用户反应就是突然集体掉线。
  • Cookie 过期:浏览器端 Cookie 到了有效期被删掉,请求里根本不会带 session id。

很多系统两个超时同时启用,于是「明明刚点了一下」也会被踢,原因是绝对超时先到了。

为什么总在半夜掉

运维半夜发版、重启服务,session 落在本地文件或者内存里,重启就清空。另外定时任务跑备份时内存吃紧,Redis 淘汰了部分 key,也会表现成随机掉线。解决办法是把 session 存到 Redis,并配置持久化,重启后还能恢复。

改进的几条思路

  • 静默续期:用户操作时刷新过期时间,绝对超时放宽到 8 小时或者一个工作日。
  • 过期前提醒:前端定时检测,提前 5 分钟弹窗提示,避免填到最后才丢。
  • 草稿保护:表单内容定时存 localStorage,重新登录后能恢复。
  • 接口返回统一错误码:比如 401 加 code 字段,前端据此跳转登录页,而不是直接报错。
  • 记住我:用长效 token 换取新的 session,重新打开浏览器时自动恢复登录态。

最后一个细节,session id 一定要设 HttpOnly 和 Secure,过期后服务端必须销毁对应记录,只在客户端删 Cookie 不算真正注销。