websocket弱网异常断开需主动心跳探测(25–30秒间隔,5–8秒超时)、精准识别onclose.code(1006为tcp强制断开)、节制重连(指数退避上限5次)并严格对齐服务端超时配置。

WebSocket 在弱网环境下异常断开,不能靠 onerror 捕获,必须主动探测、精准识别、节制重连。核心不是“等它断”,而是“提前发现并可控恢复”。
主动心跳检测(防静默断开)
弱网下 TCP 连接可能已失效,但 socket.readyState === WebSocket.OPEN 仍为真——这是典型的“假死”。浏览器不会触发 onclose 或 onerror,必须自己发心跳并设超时确认:
- 用应用层心跳更稳妥:发送
{"type":"heartbeat"},服务端返回{"type":"ack"},客户端用setTimeout控制等待窗口(建议 5–8 秒) - 心跳间隔设为 25–30 秒,略小于服务端 idle timeout(如 EMQX 的
heartbeat=30s),避免被 NAT 或防火墙单向切断 - 发送心跳后立即启动独立定时器;若未在窗口内收到响应,就调用
socket.close(4999, 'heartbeat timeout')主动终结,再触发重连
精准识别断开原因(看 code,不猜 reason)
onclose 是唯一可靠入口,但必须读取 event.code 才能定位根因:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
event.code === 1006:TCP 层被强制 RST(Nginx、运营商 NAT、iOS 后台回收等),reason通常为空,onerror完全静默 -
event.code === 1001或reason含"going away":服务端主动关闭,查服务端日志中 heartbeat timeout、read timeout 等关键词 -
event.code === 4001或reason含"auth failed":属业务逻辑问题(如 token 过期),与连接稳定性无关
节制重连(防重连风暴)
裸调 new WebSocket() 重连等于给服务端刷 DDoS。真实场景需带状态锁和指数退避:
- 用计数器
reconnectAttempts+setTimeout(..., 1000 * Math.pow(2, attempts))实现指数退避,上限建议设为 5 次 -
onopen中重置计数器,否则一次成功后下次断连会沿用旧指数 - 重连前先执行
socket?.close(1000, 'reconnecting'),避免残留连接占用资源 - 用
let socket = null+if (socket && socket.readyState === WebSocket.CONNECTING) return防止并发发起多次连接
对齐中间件超时配置(关键硬约束)
服务端或 Nginx/Tomcat/ALB 的超时值若小于心跳周期,等于主动制造 1006。这不是建议,是必须对齐的硬性约束:
- Nginx 必须同时满足:
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" -
proxy_read_timeout必须 ≥ 心跳间隔 ×2 + 网络抖动缓冲(例如心跳 30s,此项至少设为 90,生产环境建议设为 86400) - 检查 Tomcat 的
connectionTimeout、Node.js 的server.timeout、EMQX 的idle_timeout,全部需 ≥ 心跳间隔
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










