浏览器 WebSocket API 易踩四大坑:readyState 判断不严(构造后立即 send 报错)、send() 过早调用(仅 readyState === 1 可用)、onerror 不处理导致重连失效(错误无详情,需结合 onclose 的 code/reason 判断)、close() 乱传 code(必须为 1000–4999 整数)。

直接说结论:浏览器原生 WebSocket API 极简但易踩坑,readyState 判断不严、send() 调用过早、onerror 不处理就丢、close() 乱传 code 是最常导致连接异常或静默失败的四个点。
WebSocket 构造与 readyState 状态判断必须配对使用
不能只靠 new WebSocket(url) 就认为连接可用。构造后 readyState 立即是 0(CONNECTING),不是 1(OPEN)。很多代码直接在 new 后立刻调用 send(),结果报错 InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state。
正确做法是只在 onopen 回调里发数据,或者手动轮询检查:
const socket = new WebSocket('wss://api.example.com');
socket.onopen = () => {
socket.send(JSON.stringify({ type: 'auth', token: 'xxx' }));
};
// ❌ 错误示例:没等 onopen 就 send
// socket.send('hello'); // 报错
-
readyState === 0:握手还没完成,任何send()都会失败 -
readyState === 1:唯一可安全send()的状态 -
readyState === 2或3时调用send()不报错但无效,数据直接丢弃
send() 支持的数据类型和二进制传输陷阱
send() 接收 string、Blob、ArrayBuffer,但类型决定后续解析方式。默认接收文本消息为字符串,但若服务端发的是二进制帧,而客户端没设 binaryType,event.data 可能是 ArrayBuffer 也可能是 Blob,行为不一致。
关键控制点是 socket.binaryType,它必须在连接打开前或刚打开时设置(onopen 里设最稳妥):
socket.binaryType = 'arraybuffer'; // 或 'blob'
socket.onmessage = (e) => {
if (e.data instanceof ArrayBuffer) {
const view = new Uint8Array(e.data);
console.log('bytes:', view);
}
};
- 设成
'arraybuffer'后,所有二进制消息都以ArrayBuffer形式到达,适合做位操作或解码 - 设成
'blob'更省内存,适合大文件下载,但读取需blob.arrayBuffer()或blob.text() - 不设默认值是
'blob',但某些浏览器旧版本可能表现不同,显式声明更可靠
onerror 和 onclose 必须配合看,否则重连逻辑会失效
onerror 触发时,连接不一定已断开;它只是“出错了”,之后大概率触发 onclose,但不是 100%。更重要的是:onerror 不带任何错误详情,event 参数为空对象 —— 它只是个信号,不是诊断依据。
真正有用的关闭信息在 onclose 的 event.code 和 event.reason 里:
socket.onclose = (e) => {
console.log('closed with code:', e.code, 'reason:', e.reason);
console.log('wasClean?', e.wasClean); // true 表示是正常握手关闭
};
// 常见 code:
// 1000:正常关闭
// 1006:连接被意外中断(如网络闪断),wasClean === false
// 4001+:自定义业务码,需和服务端约定
-
wasClean === false是判断是否需要重连的关键指标 -
code === 1005表示服务器没传关闭码,属于中性状态,一般不重连 - 不要在
onerror里直接new WebSocket()重连,容易雪崩;应节流 + 指数退避
close() 方法的 code 参数不是随便填的
socket.close(code, reason) 主动关闭时,code 必须是规范定义的整数(1000–4999),且 1000–2999 是 WebSocket 标准码,3000–4999 是应用自定义区间。填错会导致服务端无法识别关闭意图,甚至拒绝关闭握手。
常见误用:
- 传字符串如
close('1000')→ 握手失败,连接卡在CLOSING状态 - 传非法码如
close(999)或close(5000)→ 浏览器抛SyntaxError - 不传
code(即close())→ 默认用1005(无状态码),服务端可能无法区分是用户退出还是异常
推荐写法:
// 正常退出 socket.close(1000, 'user logout'); // 临时故障需重连 socket.close(4001, 'reconnect soon');
实际项目里,code 的选择要和服务端协议对齐,否则 onclose 里的 event.code 会和预期不符 —— 这个细节在调试连接生命周期时最容易被忽略。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











