readystate为0时调用send()必然失败,因握手未完成、底层socket未就绪;长期卡在0的主因包括服务端未返回101响应、协议/证书错误、dns解析失败或小程序重复创建实例等。

ReadyState 为 0(CONNECTING)时调用 send() 必然失败,这不是 bug,是规范强制行为——连接握手未完成,底层 socket 尚未就绪,此时发消息会被直接丢弃或抛出异常。
为什么 readyState 长期卡在 0?
不是“卡”,而是连接根本没走完握手流程。常见真实原因包括:
-
wx.connectSocket()(小程序)或new WebSocket()(浏览器)调用后,服务端未响应 101 Switching Protocols,比如 Nginx 没配Upgrade和Connection: Upgrade头 - URL 协议错误:该用
wss://却写了ws://,或证书过期导致 TLS 握手失败(浏览器控制台 Network 标签里能看到 failed 的 ws 请求) - 小程序中多次调用
connectSocket但没清理旧实例,新请求被平台限流或排队,readyState始终停留在 0 - 鸿蒙或某些 WebView 环境下,DNS 解析失败或代理配置异常,导致 TCP 连接都无法建立,
readyState不会自动跳变
send() 前必须检查 readyState === WebSocket.OPEN
别信“刚连上肯定能发”,也别依赖 onOpen 回调里的同步时机——事件触发和代码执行存在微小窗口,尤其在高并发或弱网下。正确做法是:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 每次
send()前显式判断:if (ws.readyState === WebSocket.OPEN) { ws.send(data); } - 如果
readyState是 0 或 3,应拒绝发送并记录日志,而不是重试——重试只会放大问题 - 小程序中注意:
socketTask.readyState在connectSocket后立刻读取几乎总是 0,必须等onOpen触发后再启用发送逻辑 - React 等框架中,组件重渲染可能新建
WebSocket实例,而旧实例的异步回调(如定时心跳)仍在运行,容易误操作已销毁的 socket
如何快速定位是握手失败还是发包失败?
关键看错误发生时的上下文状态,不是只盯 readyState 数值:
- 浏览器:打开 Network → Filter 输入
ws→ 找到对应连接 → 查看 Headers 里是否有101 Switching Protocols;如果没有,说明握手失败,问题在服务端或反向代理 - 小程序:在
fail回调里打印完整 err 对象,重点看err.errMsg是否含net::ERR_CONNECTION_REFUSED或request:fail timeout - 鸿蒙:查系统日志关键词
OnClose 1011(链路中断)或userdata is nullptr(socket 实例已释放),这类日志比readyState更可信 - 通用技巧:在
onError和onClose里打印ws.readyState和当前时间戳,对比是否出现 “onError 时 readyState 还是 0” —— 这基本锁定是 DNS/TCP 层失败
readyState 是个快照,不是状态机控制器。真正可靠的依据永远是事件(onOpen/onClose)+ 网络层可观测性(Headers、日志、抓包),而不是轮询一个可能滞后的数字。










