手机锁屏后WebSocket必然断开,需监听visibilitychange事件,在document.hidden为false且readyState为2或3时,延迟1500ms执行close再重连;onclose不可靠,应以readyState判断为准,避免复用旧实例。

手机锁屏后WebSocket必然断开,这不是代码写得不对,而是iOS/Android系统主动切断的——任何纯前端心跳包在熄屏后都会失效,必须结合页面可见性监听 + 状态判断 + 延迟重连。
监听页面 visibilitychange 事件触发重连
移动端锁屏或切后台时,document.hidden 会变为 true;返回前台时变回 false。这是唯一可靠、无需权限、全平台兼容的唤醒信号。
- 不要监听
blur/focus,它们在iOS Safari中不可靠,且不触发锁屏场景 - 务必在
visibilitychange回调里检查websocket.readyState,而不是直接重连——刚切回来时连接可能还“挂着”(状态为2CLOSING 或1OPEN) - 避免立即重连:系统恢复JS执行有延迟,
setTimeout(..., 1500)是经过实测的稳妥间隔,太短会报InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state
document.addEventListener('visibilitychange', () => {
if (!document.hidden && (ws.readyState === 2 || ws.readyState === 3)) {
setTimeout(() => {
ws.close();
connectWebSocket(); // 你的建连函数
}, 1500);
}
});
readyState 判断比 onclose 更可信
onclose 事件在锁屏后经常不触发,或延迟数秒才触发,甚至在iOS微信小游戏中完全丢失。依赖它做重连会导致连接空窗期长达几十秒。
-
ws.readyState === 0:正在连接,此时不应干预 -
ws.readyState === 1:正常,跳过重连 -
ws.readyState === 2:已发关闭帧但未完成,可等几秒再关再连 -
ws.readyState === 3:已彻底断开,必须重连
建议每次进入前台都统一走「先 close 再 new WebSocket」流程,而不是复用旧实例——旧实例内部状态可能已损坏,强行 send 会静默失败。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
reconnecting-websocket.js 不是银弹
ReconnectingWebSocket 库能自动重连,但它默认只响应 onclose 和 onerror,而锁屏导致的断连这两者都不稳定触发,所以它在移动端基本“失明”。
- 它无法感知
visibilitychange,也不会主动检查readyState - 若你坚持用它,必须手动 patch:
reconnect()调用要包裹在visibilitychange的!document.hidden分支里 - 它的指数退避策略(如 1s → 2s → 4s)在用户刚切回前台时反而拖慢恢复速度,建议设
maxReconnectionDelay: 1000
iOS原生App需额外配置后台模式
H5页面受限于浏览器沙箱,只能靠 visibilitychange;但如果你开发的是iOS原生App(如Unity、React Native或Swift),必须在Xcode中启用后台能力,否则系统会在挂起后30秒内强制 kill TCP连接。
- Info.plist 中添加:
UIBackgroundModes数组,包含fetch和remote-notification - 仅勾选
processing没用——iOS 13+ 已废弃该模式,fetch才是保活心跳的合法入口 - 即使开了后台模式,也不能维持长连接,而是靠周期性 fetch 触发重连逻辑,每次最多运行30秒
真正难处理的不是“怎么连”,而是“怎么判断该连”:visibilitychange 只对Web有效;原生侧要用 applicationWillEnterForeground(iOS)或 onResume(Android),且要配合网络状态检测(online 事件)交叉验证——因为用户切回来时,WiFi可能还没连上,这时盲重连只会快速耗尽重试次数。










