websocket离线判定需基于连接状态与心跳而非navigator.online:监听onclose/onerror、双向心跳验证、readystate不可靠;离线时应提示用户、降级功能、缓存消息并重连同步;主动注销(code 1000)禁自动重连,异常断开(wasclean=false)启用指数退避重连。

WebSocket 本身不感知“离线”,客户端所谓“离线状态”其实是连接断开、无法通信的体现。要真正处理它,不能只靠 navigator.onLine,而得结合连接状态、心跳验证和业务逻辑做主动判断与响应。
用 WebSocket 自身状态 + 心跳来真实判断离线
浏览器的 navigator.onLine 只反映系统网络接口是否开启,Wi-Fi 开着但路由器断网时它仍返回 true,完全不可靠。真正有效的离线判定必须基于 WebSocket 通信行为:
- 监听
onclose和onerror事件,它们是连接实际中断的唯一可信信号 -
readyState === WebSocket.OPEN不代表连接健康,只是“曾经连上过” - 必须实现双向心跳:客户端定时发
ping,服务端必须回pong;客户端收到pong才算连接有效,超时未收到就主动close() - 关闭事件中的
event.wasClean === false且event.code === 1006,基本可确认为异常断连(如断网、服务宕机)
离线期间的用户状态反馈与降级体验
一旦确认离线,前端需立刻告知用户,并限制依赖实时性的操作:
- UI 上显示明确提示,如“网络不稳定,消息将暂存并稍后同步”
- 禁用强实时功能:比如协作编辑光标、音视频信令、支付确认等,避免用户误操作
- 对非关键消息(如通知、日志)允许“先展示本地缓存,上线后再对账”
- 敏感操作(如密码修改、资金转账)一律拦截,强制联网后才可执行
离线消息缓存与重连后同步
离线不是停止工作,而是转入缓存模式:
- 所有待发消息先存入内存队列;页面刷新不丢数据的话,要用
localStorage或更稳妥的IndexedDB持久化 - 每条缓存消息带唯一 ID、时间戳、重试次数和过期时间(如 24 小时),便于去重和清理
- 重连成功后,按顺序重发队列中未确认的消息;建议加 100ms 间隔,避免服务端压力突增
- 接收端也要配合:重连后主动向服务端请求“上次断开后未读消息”,靠服务端消息回溯补全
注销与异常断开必须区分对待
用户点“退出登录”和网络突然中断,处理方式完全不同:
- 主动注销时,先发登出消息给服务端,再调用
ws.close(1000, "user logout"),并在重连逻辑中检查event.code === 1000和event.reason,禁止自动重连 - 异常断开(
wasClean === false)才启动指数退避重连(如 1s → 1.5s → 2.25s…),并设最大重试次数(如 5 次) - 用标志位(如
this.isManuallyLoggedOut = true)隔离两种场景,避免注销后又被自动拉回登录态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











