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; }
真正难的不是“搭起来”,而是让连接在弱网、切后台、锁屏、证书更新、服务滚动发布这些场景下依然能自动恢复——这些细节没处理好,实时性就只是幻觉。