websocket异常关闭需区分正常下线与意外失联,通过code=1006、wasclean=false识别异常,配合状态控制、指数退避(上限30秒+抖动)、心跳保活(30秒ping/5秒超时)及安全重连流程(检查closed状态、防重复、清理资源)实现稳定连接。

WebSocket 客户端异常关闭时,不能只靠 onclose 事件触发就盲目重连。关键要区分是“正常下线”还是“意外失联”,再配合状态控制、退避策略和心跳保活,才能做到稳定可靠。
识别真正的异常关闭
异常关闭最典型的信号是 event.code === 1006(abnormal closure),它代表连接在无规范关闭帧的情况下中断——比如网络断开、标签页被关、代理静默断连。此时 event.reason 通常为空,event.wasClean 为 false。而 1000(正常关闭)、1001(going away)一般不应自动重连,需结合业务逻辑判断是否属于主动退出。
- 只依赖
code做判断,不要用reason字符串匹配 -
code ≥ 4000属于自定义错误码,可结合 reason 判断是否需刷新 token 后重连 - 记录
onclose触发时间戳,辅助识别“频繁断连”(如 60 秒内超 3 次)
安全发起重连的时机与方式
不能在 onclose 回调里直接 new WebSocket()。此时旧实例可能还处于 CLOSING(2) 状态,新连接会竞争资源,甚至引发 INVALID_STATE_ERR 或内存泄漏。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 先检查
ws.readyState === WebSocket.CLOSED (3)再进入重连流程 - 用布尔标志位(如
isReconnecting = true)防止多次触发 - 用
setTimeout(fn, 0)把新建连接推入宏任务队列,避开同步冲突 - 每次重连前清理上一次的定时器、监听器和旧 ws 实例(
ws?.close())
配置合理的指数退避策略
固定间隔重连(如每秒一次)在公网环境下极易触发服务端限流或雪崩。应采用带上限和抖动的指数退避:
- 初始延迟:1000 ms
- 每次失败后延迟翻倍:
Math.pow(2, retryCount) * 1000 - 上限设为 30000 ms(30 秒)
- 叠加
Math.random() * 500防止集群客户端同时重试 - 总重试次数建议 ≤ 10 次,超限后暂停并提示用户手动操作
增强连接存活能力:心跳 + 主动探测
仅靠 onclose 不够及时——TCP 层可能长时间不通知,导致“假连接”(NAT 超时、中间设备丢包)。必须加应用层心跳:
- 连接打开后,每 30 秒发送
{"type":"ping"} - 启动一个 5 秒响应计时器,超时未收到
{"type":"pong"}就主动ws.close(4999, "no_pong") - 心跳消息中可携带 token 或时间戳,便于服务端校验有效性
- 重连成功后,立即拉取最新状态或重发待确认消息,避免 UI 滞后










