必须主动发心跳+自动重连,因onClose在微信小程序切后台、H5休眠、App无保活时均不触发;需用JSON ping/ts校验连接有效性,setTimeout递归发送防堆积,重连前检测网络与错误码,并按生命周期关闭/重建连接。

不能只靠 onClose 判断断连,所有平台都必须主动发心跳 + 自动重连,否则微信小程序静默断连、H5 页面休眠时根本收不到通知。
为什么 onClose 经常不触发
微信小程序切后台或页面不可见时,底层连接直接被系统回收,onClose 压根不执行;H5 在标签页非激活状态时,浏览器可能冻结定时器或延迟触发事件;App 端若没开后台保活权限,iOS 会强制 kill 连接,Android 各厂商策略也不一致。依赖它做断连判断等于裸奔。
- 验证方式:手动切后台 → 等 30 秒 → 回前台,看是否还有
readyState === 1,而不是等onClose日志 - 真实场景中,90% 的“假在线”都源于这个误判
- 必须用主动心跳响应(
pong)+ 时间戳校验来定义“连接有效”,而非事件回调
心跳怎么发才不丢、不卡、不叠加
用 setInterval 容易在重连时旧定时器没清干净,导致多个心跳并发发送;H5 原生 WebSocket 只接受 ArrayBuffer 或字符串,而 uni.sendSocketMessage 默认兼容两者,混用会丢包;支付宝/微信小程序对消息类型容忍度也不同。
- 统一用
JSON.stringify({ type: 'ping', ts: Date.now() })发送,别传对象或二进制 - 发之前务必检查
socketTask?.readyState === 1,否则跳过 - 用
setTimeout递归调用代替setInterval,每次发完立刻设下一次,避免堆积 - H5 端若混用原生
WebSocket,记得send()前做typeof data === 'string' ? data : JSON.stringify(data)
重连逻辑里最容易漏的三件事
重连不是“失败就 retry”,而是要结合网络状态、错误码、前后台生命周期做精细化控制。常见问题:无网络时狂试连接、401 认证失败还重连、onHide 没关 socket 导致后台持续发心跳耗电。
- 每次重连前调用
uni.getNetworkType,返回'none'时直接 return,不发起请求 - 在
onError中解析err.errMsg,匹配'fail timeout'或'fail net::ERR_INTERNET_DISCONNECTED'才重连;401/403 等认证错误直接close并提示登录 -
onHide中必须调用socketTask?.close(),onShow中再重新uni.connectSocket并重置心跳定时器 - 重连次数建议设为 5 次,第 6 次起用指数退避:
Math.min(60000, 1000 * Math.pow(2, retryCount))
最复杂的地方不在代码量,而在「心跳响应判定」和「平台行为差异」的交叉处理——比如微信小程序收到 pong 后仍可能几秒内静默断连,所以服务端超时阈值(如 45s)必须比客户端心跳间隔(如 30s)长,且客户端需额外加一个 5–10 秒的响应等待窗口,超时未收则主动 close 并重连。


















