WebSocket断连需主动心跳探测与指数退避重连:每20–30秒发{"type":"ping"}并5秒超时未收{"type":"pong"}即主动关闭;重连延迟从1000ms起翻倍+±30%抖动,上限30秒,总重试≤10次;每次重连前清理旧连接、定时器、事件监听,并动态获取新token。

后端服务重启导致 WebSocket 断连,是线上最常见、也最容易被低估的故障场景。它不会总触发 onclose,更不会总报错,而是让连接“静默失效”——页面还在跑,消息却再也收不到。真正可靠的处理方式,不是等断了再补救,而是从设计上把重连当作默认行为,并主动验证连接是否真实可用。
必须加心跳探测,不能只靠 onclose
服务端突然重启(比如容器滚动更新、进程 kill -9),客户端往往收不到标准关闭帧,readyState 可能卡在 OPEN 长达数秒甚至更久,onclose 根本不执行。这时候仅监听 onclose 就等于没做任何防护。
- 连接建立后,每 20–30 秒发送一次业务层
{"type":"ping"}消息(不要用原生 ping 帧,JS 不暴露发送接口) - 同时启动一个 5 秒超时定时器,未收到
{"type":"pong"}就立刻调用ws.close(4999, "no_pong")主动断开 - 这个间隔必须小于服务端和中间设备(如 Nginx 的
proxy_read_timeout、运营商 NAT 老化时间)的最短空闲超时阈值
重连要用指数退避 + 随机抖动
服务端刚重启完,大量客户端同一时刻发起重连请求,极易打满连接队列或触发限流,反而延长恢复时间。
- 基础延迟:从 1000ms 开始,每次失败翻倍,上限设为 30000ms(30 秒)
- 叠加 ±30% 随机抖动:
delay += Math.random() * delay * 0.3 - 总重试次数建议 ≤ 10 次;超过后暂停自动重连,改由用户手动刷新或展示明确提示
-
retryCount必须在onopen中清零,否则会继承上次失败计数
每次重连前必须清理干净
反复断连时若不清理旧资源,会出现多个 WebSocket 实例并存、定时器堆积、事件重复绑定、内存泄漏等问题。
立即学习“Java免费学习笔记(深入)”;
- 用唯一引用(如
wsRef)管理当前连接,新建前先执行wsRef?.close()并置空 - 清除上一轮的心跳定时器(
clearInterval(pingInterval))、超时计时器(clearTimeout(heartbeatTimeout)) - 移除所有事件监听器(
ws.removeEventListener或使用一次性监听) - 设置
isReconnecting = true标志位,在onclose中判断是否已在重连流程中,防止重复触发
URL 和凭证要动态生成
如果连接 URL 包含 token 或 timestamp 参数,服务端重启后旧凭证大概率已过期。直接复用会导致无限重连失败。
- 每次重连前重新调用认证接口获取最新 token,并拼接到新 URL 中
- 确保前端心跳间隔、超时阈值与服务端保活配置(如 keepalive timeout、ping interval)严格对齐
- 生产环境中,80% 的“重连不成功”问题,根源其实是前后端保活策略错配


















