锁屏后websocket断开是ios/android系统主动冻结网络所致,需用visibilitychange感知状态+web worker承载心跳重连+服务端协同兜底:监听visibilitystate切换时停心跳不close、切回时校验readystate并指数退避重连;服务端记录最后活跃时间、超时清理并推送离线摘要;pwa可结合service worker缓存pending消息。

锁屏后 WebSocket 断开不是前端代码写错了,而是 iOS/Android 系统主动冻结网络任务导致的必然现象。靠 setInterval 心跳、不关连接、反复重连这些“表面保活”手段,在锁屏 10–30 秒后基本失效。真正有效的方案是:用 visibilitychange 快速感知状态切换 + Web Worker 承载心跳与重连逻辑 + 服务端协同做连接兜底。
监听 visibilitychange 判断页面是否被锁屏或切后台
这是最轻量、兼容性最好、且必须做的第一层响应。iOS 和 Android WebView 都支持该事件,但注意它不区分“锁屏”和“切应用”,只反映页面可见性变化。
-
document.visibilityState === 'hidden'时,立刻停止主线程的心跳定时器(避免无效发包耗电),但不要调用ws.close()—— 此时连接大概率已被系统断开,强行 close 会抛InvalidStateError -
document.visibilityState === 'visible'时,不能直接复用旧ws实例,必须检查ws.readyState !== WebSocket.OPEN就触发重连 - 别依赖
setTimeout或setInterval在 hidden 状态下继续运行 —— 锁屏后它们在多数 Android WebView 和 iOS WKWebView 中会被暂停或大幅降频
把心跳和重连逻辑移到 Web Worker 中执行
主线程不可靠,Web Worker 是目前唯一能在锁屏/后台持续运行 JS 的标准机制(Chrome 80+、Firefox 79+、Safari 16.4+ 均已支持 Worker 内原生 WebSocket)。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- Worker 文件需同源,且不能访问 DOM;但可使用
self、WebSocket、setInterval、fetch - 心跳策略建议:每 25 秒
ws.send(JSON.stringify({type: 'ping'})),同时起一个setTimeout监控上次收到{type: 'pong'}的时间,超 45 秒即判定失联 - 重连必须带指数退避:
[1000, 2000, 4000, 8000, 16000],最大间隔不超过 30 秒,否则网络恢复初期容易触发重连风暴 - 主线程通过
MessageChannel向 Worker 发送业务消息,Worker 负责转发到 WS —— 避免主线程挂起时消息堆积丢失
服务端必须配合做连接状态确认和离线补偿
前端再努力也控制不了系统杀进程,所以服务端要承担“连接真实性验证”和“状态兜底”的责任。
- 每次成功建立连接后,前端向服务端上报
clientId和连接时间戳,服务端记录为 “最后活跃时间” - 服务端每 30 秒检查一次心跳上报,若超 60 秒无任何 ping/pong 或业务帧,主动清理该连接并标记为离线
- 客户端切回前台时,先发一次
/api/offline-messages?since=xxx拉取未读摘要,再发起新 WebSocket 连接 —— 避免消息空窗期 - 所有关键操作(如支付确认、协作编辑提交)必须带服务端幂等 key(如
idempotency-key: uuidv4()),防止因重复重连导致指令被执行多次
PWA 场景下用 Service Worker 缓存离线消息
如果是 PWA 应用,Service Worker 可补足 Web Worker 无法持久化数据的短板,但它本身也会被系统终止,只适合轻量级同步。
- 注册 SW 后,在
install阶段缓存鉴权接口(如/api/token),保证重连时能快速获取有效凭证 - 连接断开时,用
cache.put()把用户发出但未确认的消息存入 Cache API,标记status: "pending" - 监听
sync事件,在网络恢复后自动重发 pending 消息;注意单次 sync 最多执行 60 秒,大消息需分片 - 别指望 SW 长期驻留 —— 它可能在后台被系统回收,所以 pending 消息仍需服务端最终校验与去重
最容易被忽略的是:前端重连逻辑和服务端连接清理必须严格对齐超时窗口。比如前端设 45 秒无 pong 就断连,服务端却按 90 秒清理,就会出现大量“假在线”连接,拖垮整个长连接集群。










