Spring MVC中Session属性偶现丢失:是否存在竞态条件?
首先先提一个代码里的小笔误:你的Filter代码中使用了httpServletRequest.getParameters("MY_PARAM"),这个方法返回的是String[](参数的所有值),而你应该用getParameter("MY_PARAM")来获取单个参数值——不过这个小问题应该不是导致Session不一致的核心原因,但还是建议修正。
回到你遇到的核心问题:Filter中设置Session属性的请求,和后续Controller处理的请求使用了不同的Session,本质是两次请求的JSESSIONID不一致,导致服务器为第二次请求创建了新的Session。下面是最可能的几个原因:
1. 重定向请求未携带原Session的Cookie
你的Filter在设置Session后执行了重定向,而如果重定向的URL存在以下情况,浏览器会拒绝携带原请求的JSESSIONID Cookie:
- 协议/域名/端口不一致:比如原POST请求是
https://yourdomain.com/submit,但重定向到了http://yourdomain.com/mypage(协议从HTTPS变HTTP),或者跨子域名(比如submit.yourdomain.com重定向到www.yourdomain.com),浏览器会认为是不同站点,不会携带原来的Cookie。 - Cookie属性限制:如果你的Session Cookie配置了
Secure(仅HTTPS传输)、SameSite=Strict(严格同站)等属性,重定向场景可能触发浏览器的Cookie拦截规则。比如SameSite=Strict会阻止跨站POST请求后的重定向携带Cookie,而Secure属性的Cookie在HTTP请求中不会被发送。
2. 浏览器并发请求或Cookie未及时写入
极端情况下,用户快速触发多次请求时,浏览器可能还没来得及保存Filter响应中Set-Cookie的JSESSIONID,就发送了后续的重定向请求,导致请求没有携带正确的Session ID,服务器只能创建新Session。这种情况概率很低,但在高并发或浏览器性能较差时可能出现。
3. 分布式Session的同步延迟
如果你的应用部署在分布式环境(多实例),且使用了Redis、Memcached等外部存储来共享Session,可能会出现Session属性同步延迟:Filter在实例A设置了Session属性,但还没同步到共享存储,Controller的请求就路由到了实例B,实例B从存储中读取到的是未更新的Session(甚至是新Session)。
4. 路径错误导致跨Web应用
如果Filter中重定向的URL错误指向了同一个服务器上的另一个Web应用(不同上下文路径),那两个应用的Session是完全隔离的,Controller自然会拿到新的Session。
排查建议
- 抓包分析Cookie:出现问题时,用浏览器开发者工具查看网络请求,对比POST请求的响应头
Set-Cookie(包含JSESSIONID)和后续GET请求的请求头Cookie,确认两者的JSESSIONID是否一致。 - 检查重定向URL:确认Filter中的重定向目标URL和原请求的协议、域名、端口完全一致,没有跨站/跨协议的情况。
- 验证Cookie配置:查看应用服务器的Session Cookie配置,检查
Secure、HttpOnly、SameSite等属性是否合理,避免在重定向场景下被浏览器拦截。 - 分布式环境排查:如果是分布式部署,检查Session存储的同步机制,是否存在延迟或一致性问题,比如Redis的主从同步延迟。
- URL重写处理:如果你的应用需要支持禁用Cookie的浏览器,确保重定向时使用
response.encodeRedirectURL(redirectUrl)来自动拼接JSESSIONID到URL中,避免丢失Session标识。
内容的提问来源于stack exchange,提问作者PDStat

