websocket是唯一原生支持真正双向通信的浏览器方案,因其基于tcp长连接、握手后复用同一连接并免http头开销;fetch和xmlhttprequest本质为单向请求-响应模型,轮询会导致延迟高、开销大、连接频繁重建。

WebSocket 是浏览器中实现真正双向通信的唯一原生方案,不需要轮询、不依赖 HTTP 请求-响应模型,连接建立后客户端和服务器可随时互发消息。
为什么不能用 fetch 或 XMLHttpRequest 做双向通信
它们本质是单向请求工具:客户端发一次,服务端回一次,之后连接就断了。即使加 setInterval 轮询,也会带来明显延迟、重复 header 开销、连接频繁重建等问题。而 WebSocket 握手成功后复用同一个 TCP 连接,后续所有数据帧都不带 HTTP 头,协议开销极小。
常见错误现象包括:
- 用户看到“新消息”总比实际晚 2–5 秒(轮询间隔导致)
- 服务端日志里每秒出现数百个
GET /api/notify请求(其实是假实时) - 移动端耗电快、流量消耗异常高(高频短连接)
WebSocket 连接必须用 wss:// 吗
不是必须,但生产环境几乎必须。HTTP 页面加载时,浏览器会阻止非加密的 ws:// 升级请求(Mixed Content 报错),控制台直接报 Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS。
所以实际部署要注意:
- 前端页面走
https://→ 后端 WebSocket 地址必须用wss:// - 本地开发用
http://localhost时,ws://可以临时工作,但别依赖它 - Nginx 反向代理
wss://需显式配置Upgrade和Connection头,漏掉就会卡在readyState === 0
如何判断连接是否真正可用,而不是“假在线”
readyState 值为 1(OPEN)只代表握手完成,不代表网络通或服务端逻辑就绪。真实场景中常遇到:
- 连接已打开,但服务端没做鉴权,直接关闭(
onclose触发,event.code是4001类自定义码) - 防火墙或代理中途静默断连,客户端仍显示
readyState === 1 - 服务端进程崩溃,但 TCP 连接未及时 FIN,客户端无感知
因此必须加心跳:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
let heartbeatTimer;
socket.onopen = () => {
heartbeatTimer = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
};
socket.onmessage = (e) => {
const data = JSON.parse(e.data);
if (data.type === 'pong') return; // 忽略心跳响应
// 处理业务消息
};
socket.onclose = () => {
clearInterval(heartbeatTimer);
};
服务端广播时为什么有些客户端收不到消息
最常见原因是没检查 client.readyState === WebSocket.OPEN。Node.js 的 ws 库中,client.send() 对已断开但尚未触发 close 事件的连接会静默失败,不抛错也不重试。
正确写法必须逐个判断状态:
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(payload);
} else {
console.warn('Dropped message: client not ready', client.readyState);
}
});
另外注意:ws 默认不支持跨域,若前端域名与服务端不一致,需手动设置 verifyClient 或启用 options.origin 白名单,否则连接直接被拒绝,前端看不到任何错误,只有 onerror 被触发一次。










