移动端网络切换时websocket必然断开,需前端监听onclose并实施指数退避重连(1s→3–5s±1s抖动→15–30s),配合服务端心跳超时≤90秒、重连后认证绑定与离线消息补发。

移动端切换网络时 WebSocket 连接必然断开
这是 TCP 层面的客观限制:4G 切 WiFi、飞行模式开关、后台冻结等操作都会导致底层 socket 被系统回收,onclose 事件一定会触发。Workerman 服务端对此无感知、也无法干预——重连必须由前端主动发起。
前端必须监听 onclose 并实现指数退避重连
固定间隔(如 3 秒)会引发雪崩式请求,尤其在弱网或模组冷启动场景下完全失效。真实设备网络恢复有延迟,比如 SIM 卡重注册可能耗时 8 秒,盲目重试只是空转。
- 首次断开:立即尝试重建
new WebSocket() - 连续失败 2 次:延迟升至 3–5 秒,并加 ±1 秒随机抖动
- 连续失败 5 次:延迟拉到 15–30 秒,同时检查
navigator.onLine和信号强度(如modem.getSignalLevel()) - 4G 模组必须监听 AT 响应(如
+CGATT: 1、+CREG: 1,1),仅当注册成功后再建连接
服务端要配合做心跳超时控制,不能只靠客户端
运营商 NAT 防火墙普遍在 60–120 秒内静默回收空闲连接,Linux 的 tcp_keepalive_time 在此场景下完全无效。服务端若不主动探测,会误判“连接还活着”,导致消息堆积或状态错乱。
-
onMessage第一行必须无条件更新$connection->lastMessageTime = time(),不管消息是否是 JSON、能否解析 - 心跳建议用二进制前缀(如
\x01)或子协议区分,避免依赖 JSON 结构导致解析失败就跳过时间戳更新 - 服务端超时阈值必须 ≤90 秒(容忍一次心跳丢失),低功耗设备可放宽至 150 秒
- 未绑定 UID 的匿名连接也要初始化
lastMessageTime,否则定时器遍历时会触发 PHP Notice
重连后需重新绑定用户身份和业务上下文
单纯重建 WebSocket 连接不等于业务恢复。用户可能已切换账号、订单状态已变更、或上次连接携带的 JWT 已过期。
- 重连成功后,前端应立刻发送带签名的认证包(如
{"type":"auth","token":"..."}) - 服务端收到后调用
$connection->bindUid(),并校验 token 有效性与权限范围 - 若旧连接仍残留未处理完的消息(如离线推送),需通过 Redis 或消息队列补发,不能假设“重连即同步”
- 避免在
onClose或onMessage中做重连逻辑——这些回调不在 Worker 初始化上下文中,无法安全重建资源
setTimeout,而在于让前端重连策略理解模组真实的网络生命周期,并和服务端心跳、认证、上下文恢复形成闭环。任何一环脱节,都会表现为“看起来连上了,但消息收不到”。











