WebSocket是独立于HTTP的全双工TCP协议,非HTTP升级版;关键在稳定性、可扩展性与兜底机制,而非仅连接建立。
WebSocket 不是 HTTP 的升级版,而是独立的全双工通信协议;用它做实时通信,关键不在“怎么连”,而在“怎么稳、怎么扩、怎么兜底”。
WebSocket 是浏览器与服务器之间建立的持久化 TCP 连接,双方可随时主动发消息。它不是轮询(AJAX),也不依赖 HTTP 长连接(SSE)——握手阶段走一次 HTTP Upgrade 请求,之后就完全脱离 HTTP 协议栈。
常见误解:
new WebSocket() 成功就代表通信可靠(实际只表示握手成功,后续网络中断不会自动重连)ws、socket.io,或 Nginx 的 proxy_http_version 1.1 + Upgrade 转发)浏览器原生 WebSocket API 极简,但缺重连、心跳、错误分类等生产必需能力。别直接裸用 new WebSocket(url)。
实操建议:
pong 或客户端超时未收,就主动 close() 并触发重连onerror 里重连:它不区分网络错误、证书错误、服务不可达,且可能被多次触发;应以 onclose 为主判断依据简单心跳示例(客户端):
let ws = null;
let pingTimer = null;
function connect() {
ws = new WebSocket('wss://api.example.com/ws');
ws.onopen = () => {
console.log('connected');
startPing();
};
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
// 处理业务消息
};
ws.onclose = () => {
console.log('disconnected, retrying...');
clearTimeout(pingTimer);
setTimeout(connect, 1000); // 简单退避
};
}
function startPing() {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
pingTimer = setTimeout(startPing, 30000);
}
ws 库搭一个最小可用 WebSocket 服务要注意什么?ws 是最轻量、最贴近协议标准的库,但它不提供房间、广播、鉴权等上层功能——这些得自己补。
关键点:
origin 或 token:WebSocket 握手请求是 HTTP GET,可在 verifyClient 钩子中检查 req.headers.origin 或 req.url 带的 token 参数ws.Server 默认不限制并发,需手动控制(如用 maxPayload 防大包、用 verifyClient 拒绝非法请求)ws.readyState === WebSocket.OPEN:异步操作中连接可能已断,否则会抛 InvalidStateError
ws.send() 直接发对象:它只接受 string 或 Buffer,JSON 要先 JSON.stringify()
最小服务示例(带基础鉴权):
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws, req) => {
const url = new URL(req.url, 'http://localhost');
const token = url.se
archParams.get('token');
if (!token || token !== 'my-secret') {
ws.close(4001, 'Invalid token');
return;
}
ws.on('message', (data) => {
try {
const msg = JSON.parse(data.toString());
console.log('received:', msg);
// 回复确认
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ ack: msg.id }));
}
} catch (e) {
ws.close(4002, 'Invalid JSON');
}
});
});
90% 的线上 WebSocket 故障不出现在业务逻辑,而出现在反向代理或证书配置上。
典型问题:
Upgrade 请求:必须显式配置 proxy_set_header Upgrade $http_upgrade 和 proxy_set_header Connection "upgrade"
ws:// 会被浏览器拦截:前端必须用 wss://,且证书要有效(自签名证书需用户手动信任)pingInterval 主动保活Nginx 关键配置片段:
location /ws {
proxy_pass https://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 60;
}
真正难的不是“搭起来”,而是让连接在弱网、切后台、锁屏、证书更新、服务滚动发布这些场景下依然能自动恢复——这些细节没处理好,实时性就只是幻觉。