不能仅依赖 navigator.online 判断重连,需用 fetch('/api/ping') 等主动探测;必须配 abortcontroller 设超时(如5秒),避免挂起;请求专用健康端点并后端校验依赖;高频失败需防抖。

不能只靠 navigator.onLine 判断是否该重连,它在 WiFi 连着但路由器断网、代理失效、DNS 拒绝时仍返回 true;真正要重连的信号,得来自主动探测(如 fetch('/api/ping') 或 WebSocket 的 onclose)。
fetch 心跳检测怎么写才不卡死也不误判
浏览器原生的网络状态 API 不反映服务可达性,必须自己发请求验证后端是否真通。用 fetch 做心跳最轻量,但默认无超时,容易挂住。
- 必须用
AbortController控制超时,比如 5 秒没响应就当失败:const controller = new AbortController(); setTimeout(() => controller.abort(), 5000); fetch('/api/ping', { signal: controller }) - 别请求
/或/favicon.ico—— 这些可能被 CDN 缓存或绕过真实服务,应走专用 endpoint(如/api/ping或/health) - 后端
/health要检查数据库连接、核心依赖,不能只是return 200 OK - 高频抖动时会反复触发成功/失败,需加防抖:比如连续两次失败间隔
WebSocket 重连为什么 onclose 不触发
很多重连逻辑“写了却没用”,根本原因是事件监听器没绑对时机或被覆盖。WebSocket 实例创建后若未及时绑定,初始握手失败(如 401、403)就可能漏掉 onclose。
-
onclose必须在new WebSocket(url)之后、readyState === 0(CONNECTING)时立即绑定,否则收不到初始错误 - 别用
ws.onclose = handler反复赋值——后一次会覆盖前一次;改用ws.addEventListener('close', handler),支持多次注册且不冲突 -
onerror不可靠:它常不带错误信息,且在网络解析中会被频繁触发,不适合作为主断连依据 - 真正可信的是
onclose中的event.wasClean === false或event.code === 1006(异常关闭)
重连策略怎么避免压垮服务端和客户端
无脑 setTimeout(connect, 1000) 在弱网下会瞬间打出几十个连接请求,服务端连接数爆、客户端内存涨、还可能被浏览器限流。
- 用指数退避:起始延迟 1000ms,每次 ×1.6(比 ×2 更平滑),上限硬设为 30000ms(30 秒)
- 必须设最大重试次数(如
maxRetries = 5),超限后停止自动重连,等用户点击“重试”或online事件唤醒 - 每次重连前先
clearTimeout(this.reconnectTimer),防止旧定时器在新连接成功后误执行 - 重连前检查
document.hidden:页面在后台(App 切到后台、手机锁屏)时暂缓重连,省电也避免无效连接
重连成功后消息为什么还会乱或重复
重连不是“连上就完事”。旧连接可能还在收包,新连接已建立,两者消息混在一起,或 send 时目标连接已失效,导致消息丢失、重复、错序。
- 发消息前必须校验
ws.readyState === WebSocket.OPEN,别假设“刚 new 完就一定 ready” - 给每个 WebSocket 实例打唯一标识(如
ws._id = Date.now() + '-' + Math.random().toString(36).substr(2, 9)),在onmessage中过滤掉非当前连接的消息 - 重连成功后,不要盲目重发未确认消息——除非协议层支持消息 ID 和 ACK,否则可能破坏业务顺序
- 每次重连前调用
wsRef?.close()并设wsRef = null,确保单实例;清除旧定时器、事件监听器,避免资源泄漏
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











