WebSocket是独立于HTTP的全双工TCP协议,非HTTP升级版;关键在稳定性、可扩展性与兜底机制,而非仅连接建立。

WebSocket 不是 HTTP 的升级版,而是独立的全双工通信协议;用它做实时通信,关键不在“怎么连”,而在“怎么稳、怎么扩、怎么兜底”。
WebSocket 是什么?和 AJAX / SSE 有什么本质区别?
WebSocket 是浏览器与服务器之间建立的持久化 TCP 连接,双方可随时主动发消息。它不是轮询(AJAX),也不依赖 HTTP 长连接(SSE)——握手阶段走一次 HTTP Upgrade 请求,之后就完全脱离 HTTP 协议栈。
常见误解:
- 以为
new WebSocket()成功就代表通信可靠(实际只表示握手成功,后续网络中断不会自动重连) - 把 WebSocket 当作“更快的 AJAX”来用(它不支持请求/响应语义,没有状态码、headers、自动重试)
- 忽略服务端必须部署 WebSocket 兼容服务(Node.js 的
ws、socket.io,或 Nginx 的proxy_http_version 1.1+Upgrade转发)
前端怎么安全地创建并维持一个 WebSocket 连接?
浏览器原生 WebSocket API 极简,但缺重连、心跳、错误分类等生产必需能力。别直接裸用 new WebSocket(url)。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 用封装层管理生命周期:连接中、重连中、断开、失败,每种状态都显式处理
- 必须加心跳(ping/pong):服务端没发
pong或客户端超时未收,就主动close()并触发重连 - 重连要退避:首次 1s,失败后 2s、4s、8s…最大不超过 30s,避免雪崩式重连
- 不要在
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);
}
Node.js 后端用 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.searchParams.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');
}
});
});
为什么上线后 WebSocket 经常“假连”或“秒断”?Nginx 和 TLS 是最大雷区
90% 的线上 WebSocket 故障不出现在业务逻辑,而出现在反向代理或证书配置上。
典型问题:
- Nginx 默认不转发
Upgrade请求:必须显式配置proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade" - HTTPS 下用
ws://会被浏览器拦截:前端必须用wss://,且证书要有效(自签名证书需用户手动信任) - 某些云厂商 LB(如阿里云 SLB)默认关闭 WebSocket 支持,需单独开启“长连接”或“WebSocket 协议识别”开关
- 移动端弱网下,TCP Keepalive 时间过长(Linux 默认 7200s),导致 NAT 设备提前清空连接表;需在服务端设置
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;
}
真正难的不是“搭起来”,而是让连接在弱网、切后台、锁屏、证书更新、服务滚动发布这些场景下依然能自动恢复——这些细节没处理好,实时性就只是幻觉。










