Session丢失主因是Cookie的Domain未设为父域example.com、Path未设为/、SameSite策略拦截及Session未统一存储。需统一配置Domain、Path、SameSite=None+Secure,且Session存Redis并保持密钥与时间同步。
Session 丢失是因为 Cookie 的 domain 没配对
多服务器(比如 app1.example.com 和 app2.example.com)共用一套登录态,但用户一跳转就登出——大概率是后端设的 set-cookie 中 domain 属性写死了子域名,导致浏览器不把 cookie 带给其他子域。
正确做法是统一设为父域:Domain=example.com(注意不带前导点,现代浏览器已不认 .example.com 这种写法);同时确保所有服务都用 HTTPS,否则浏览器会直接忽略带 Secure 标志的 Cookie。
- 如果用 Nginx 反向代理,别在
proxy_cookie_domain里硬写死某个子域,改用proxy_cookie_domain ~^(.+)$ $1;或显式重写为example.com - Spring Boot 用户注意:
server.servlet.session.cookie.domain配置项必须显式设为example.com,默认是空,即只作用于当前 host - Node.js + Express 用户:设置
res.cookie(..., { domain: 'example.com' }),不能漏掉这个选项
Path 配置不对会让 Cookie 在部分路由下不可见
Cookie 的 Path 决定它在哪些 URL 路径下被自动带上。比如后端设了 Path=/admin,那访问 /api/user 就不会发这个 Cookie——Session ID 找不着,自然 401。
绝大多数场景下,应该设为 Path=/,除非你有明确隔离需求(如测试环境挂 /staging 下,不想和正式路径混用)。
- Java Servlet 容器(Tomcat/Jetty):通过
context.setSessionCookiePath("/");或启动参数控制 - PHP 用户注意:
session_set_cookie_params(['path' => '/'])必须在session_start()前调用 - 检查响应头:
curl -I https://app1.example.com/login看Set-Cookie字段里的Path=值是否符合预期
同一域名下多个应用共享 Session 的实际约束
光靠 Cookie 的 Domain 和 Path 对齐还不够——Session 数据本身得能跨服务读取。常见错误是每个服务各自用内存存 Session,换机器就丢。
必须把 Session 存到外部统一存储,且序列化格式、加密密钥、过期策略要一致。
- 推荐方案:Redis + 统一 session key 命名前缀(如
sess:),所有服务配置相同的redis.host和redis.password - 密钥不一致会导致解密失败,表现为“Cookie 有值但服务端解析不出 session id”,错误日志里常出现
InvalidSessionIdException或类似提示 - 时钟不同步也会出问题:如果某台服务器时间快 5 分钟,它生成的 Cookie 可能被另一台服务器判定为已过期
浏览器同站(SameSite)策略正在悄悄拦截跨子域请求
Chrome 80+ 默认启用 SameSite=Lax,而 Lax 模式下,跨子域的 POST 请求(比如从 app1.example.com 提交表单到 app2.example.com)不会携带 Cookie——Session 就断了。
解决方案不是简单改成 SameSite=None,那必须搭配 Secure(HTTPS),否则浏览器直接拒收。
- 确认你的所有子域都跑在 HTTPS 上,否则
SameSite=None; Secure会被忽略 - Nginx 示例:用
proxy_cookie_flags ~ secure samesite=none;强制补全标志 - Express 用户:
res.cookie('connect.sid', ..., { sameSite: 'none', secure: true }) - 别忘了测试:打开 Chrome DevTools → Application → Cookies,看对应 Cookie 的
SameSite列是否显示None
最麻烦的不是配错,而是部分旧浏览器不支持 SameSite=None,遇到 IE11 或老版 Safari 就得降级处理——这时候得靠前端加 credentials: 'include' 和后端做 User-Agent 兜底判断。











