WebSocket断开时无法自动缓冲发包,需代理构造函数、封装send方法、维护离线队列并结合状态监听与重连策略实现可靠消息传递。

WebSocket在网络断开时无法自动拦截发包并暂存,因为底层 TCP 连接一旦中断,ws.send() 会立即抛出错误(如 InvalidStateError 或直接静默失败),而浏览器不提供“发送前网络可达性检查”或“自动缓冲未送达消息”的原生机制。真正的做法是:**主动代理 WebSocket 实例 + 封装 send 方法 + 维护离线队列 + 结合连接状态与重连策略**。
代理 WebSocket 构造函数,统一接管所有实例
必须在页面脚本执行前注入代理逻辑(如通过 DevTools Console、油猴脚本或构建期注入),缓存原生构造函数后重写:
- 用
const NativeWebSocket = window.WebSocket缓存原始构造器,避免递归 - 覆盖
window.WebSocket,返回包装后的类,确保所有new WebSocket(...)都走代理 - 代理类需保存原始 URL、协议参数,并在实例化时绑定状态监听和队列管理逻辑
封装 send 方法,实现离线缓冲与重发
不能直接改写 ws.send 原方法体,而应返回一个代理实例,在其 send 方法中做判断:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
- 检查
ws.readyState === WebSocket.OPEN;若非 OPEN 状态(如 CONNECTING、CLOSING、CLOSED),不调用原生send,而是将数据推入内存队列(如pendingQueue.push({ data, timestamp })) - 队列建议用数组 + 时间戳标记,便于后续按序/去重/超时清理
- 注意:二进制数据(
Blob、ArrayBuffer)需深拷贝或转为可序列化格式(如 base64)再入队,避免引用失效
监听连接状态变化,触发队列重发
队列不会自动清空,必须靠状态迁移驱动:
- 在
onopen回调中启动一个“批量重发”任务:遍历队列,逐条调用原生send;成功则shift(),失败则保留或标记重试 - 在
onclose(尤其是event.code === 1006)后,不再尝试发送,只记录断连并维持队列待命 - 配合指数退避重连——重连成功且
readyState === OPEN后,才触发队列投递,避免新连接未稳就塞满数据
补充关键细节,防止常见失效
仅做 send 拦截还不够,需配套处理边界场景:
- 用户手动调用
ws.close()时,应清空队列或标记为“已放弃”,避免误重发 - 设置最大队列长度(如 50 条),超出后丢弃最旧消息或抛警告,防内存泄漏
- 若消息含时效性(如聊天消息、行情快照),入队时记录 TTL,重发前校验是否过期
- 服务端需支持幂等写入(如带唯一 ID 或版本号),避免重发导致重复业务动作

















