Spring Boot 1.5.13 WebSocket连接30分钟自动关闭问题求助
哥们,我维护老项目时也碰到过一模一样的情况——WebSocket消息收发都正常,但过段时间就因为HTTP会话过期被踢掉,错误码1008。结合你的代码和配置,给你几个针对性的解决方案:
1. 解除WebSocket与HTTP会话的绑定
你的错误提示明确指向“已结束的认证HTTP会话”,说明Spring的WebSocket默认和HTTP会话绑定了。哪怕你发了WebSocket心跳,HTTP会话还是会按自身规则过期,进而触发WebSocket连接终止。
解决思路是自定义握手拦截器,在握手阶段移除WebSocket对HTTP会话的依赖:
public class NoHttpSessionBindingInterceptor implements HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { // 移除HTTP会话属性,让WebSocket连接不再依赖它 attributes.remove("HTTP_SESSION"); return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { // 无需额外操作 } }
然后在WebSocket配置里注册这个拦截器:
@Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler( new CustomExceptionWebSocketHandlerDecorator(socketHandler), ENDPOINT ) .addInterceptors(new NoHttpSessionBindingInterceptor()) // 新增这一行 .setAllowedOrigins("*"); }
这样WebSocket连接就和HTTP会话彻底解绑,HTTP会话过期也不会影响它的存活了。
2. 用WebSocket心跳刷新HTTP会话
如果业务上必须保留WebSocket与HTTP会话的绑定(比如需要从会话里取用户信息),那可以在收到WebSocket消息(包括你的心跳)时手动刷新HTTP会话:
public class HttpSessionRefreshDecorator extends WebSocketHandlerDecorator { public HttpSessionRefreshDecorator(WebSocketHandler delegate) { super(delegate); } @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { // 获取绑定的HTTP会话并触发刷新 HttpSession httpSession = (HttpSession) session.getAttributes().get("HTTP_SESSION"); if (httpSession != null) { // 通过设置任意属性触发会话刷新 httpSession.setAttribute("last_websocket_activity", System.currentTimeMillis()); } // 继续执行原消息处理逻辑 super.handleTextMessage(session, message); } }
然后用这个装饰器包裹你的handler:
registry.addHandler( new HttpSessionRefreshDecorator(new CustomExceptionWebSocketHandlerDecorator(socketHandler)), ENDPOINT ) .setAllowedOrigins("*");
这样每次你发送WebSocket心跳时,都会同步刷新HTTP会话,避免它提前过期。
3. 确认session超时配置真的生效
虽然你设置了server.servlet.session.timeout=6h,但Spring Boot 1.5.x在某些场景下(比如Tomcat版本差异)可能不会正确读取这个配置。你可以启动项目后,查看Tomcat启动日志,搜索“session timeout”,确认实际生效的超时时间是不是6小时。如果没生效,试试直接配置Tomcat的参数:
# Tomcat会话超时配置(单位:分钟) server.tomcat.session-timeout=360
最后小提醒
你的WebSocket心跳是必须的,但最好做成双向的——客户端发心跳后,服务器也响应一条消息,这样既能维持WebSocket连接本身,也能确保HTTP会话的刷新逻辑正常触发。
内容的提问来源于stack exchange,提问作者Sebastian

