WebSocket长连接需主动维护,核心是心跳机制:客户端定时发送应用层ping消息(如{"type":"ping"}),服务端及时响应pong;心跳间隔应设为最短中间设备超时值的1/3(如Nginx默认60秒则设20秒),并配套3–5秒超时判定,配合双定时器、状态校验、后台暂停、资源清理及指数退避重连。

WebSocket 长连接不是“连上就完事”,而是需要主动维护的动态链路。真正导致断连的,往往不是显式报错,而是中间设备(如 Nginx、云负载均衡、运营商 NAT)在空闲时静默切断连接——此时 readyState 仍显示 OPEN,onclose 不触发,消息发不出去也不报错。解决这个问题,核心就是用心跳检测把“假连”揪出来。
心跳机制必须自己实现,不能依赖 TCP keepalive
TCP 层的 keepalive 默认超时通常长达 2 小时,对 WebSocket 完全无效。所有实际部署中起作用的空闲超时都更短:Nginx 默认 proxy_read_timeout=60s,阿里云 SLB 常为 90s,移动网 NAT 可低至 30s。你的心跳间隔必须比其中最短的那个更激进,否则保活就形同虚设。
- 推荐取值:心跳间隔设为最短超时值的 1/3,例如服务端或网关超时是 60 秒,心跳就设为 20 秒
- 不要只设
ping_interval,必须配套ping_timeout(如 3–5 秒),用于判定单次响应是否失效 - 浏览器原生 WebSocket API 不暴露 Ping/Pong 控制帧,所以要用应用层消息模拟,比如发送
{"type":"ping"},服务端返回{"type":"pong"}
前端心跳逻辑要防漏、防重、防卡死
一个健壮的前端心跳不只是定时发包,更要覆盖状态判断、超时兜底和资源清理。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 每次发心跳前,必须检查
ws.readyState === WebSocket.OPEN,避免向关闭中的连接发消息报错 - 采用双定时器设计:一个负责定时发 ping,另一个负责监控 pong 是否按时到达;后者超时即判定连接死亡
- 页面切后台(
visibilityState === 'hidden')时暂停心跳定时器,但不要调ws.close(),避免重复关闭引发异常 -
ws.close()后必须显式clearInterval,否则定时器持续运行,造成内存泄漏和重复发包
服务端必须正确响应,且配置显式支持
光客户端发 ping 没用,服务端得能收、能回、不丢包。很多框架默认不处理应用层心跳,需手动开启或编码支持。
- Spring Boot 的 WebSocket 需配置
enablePingPong=true才响应原生帧;若走应用层消息,则要在@MessageMapping或消息处理器里识别ping并立即返回pong - 用
wscat -c wss://your.domain/ws连上后手动发{"type":"ping"},确认能否收到{"type":"pong"},这是最快速的服务端验证方式 - 服务端也应设置连接空闲超时(如 Netty 的
IdleStateHandler),但该值应略大于客户端心跳间隔,留出网络延迟余量
断线重连不能靠异常驱动,而要由心跳超时触发
静默断连下,WebSocketConnectionClosedException 很可能根本不会抛出。等 send() 失败再重连,已经晚了——数据早就断层了。
- 重连动作必须由心跳失败(连续多次未收到 pong)直接驱动,而非等待业务消息发送失败
- 重连前加
sleep(1s),防止密集重试被服务端限流或触发熔断 - 区分手动关闭(如用户点击“退出”)和自动断连,前者设标记
isManualClose = true,避免误触发重连 - 建议采用指数退避策略:首次重连延时 1s,失败则 2s、4s、8s…并设最大重试次数(如 5 次),避免无限循环

















