WebSocket 与 HTTP 的区别

HTTP 是请求响应的短连接模型:浏览器发请求、服务器回响应,一次交互就结束,服务器没法主动把消息推给浏览器。聊天、行情、协同编辑这类实时场景,如果一直靠轮询,要么延迟高,要么浪费大量请求。WebSocket 提供一条浏览器与服务器之间的长连接,双向、低延迟,是实时通信的标准方案。

本文核心知识点
  • 长连接建立后一直保持,双向收发。
  • 握手从 HTTP 升级协议建立连接。
  • 心跳用 ping 与 pong 保活连接。
  • 集群广播多节点下的消息分发。
WebSocket 实时通信配图:蓝色渐变背景中央服务器机柜方块与四周浏览器、手机、平板客户端方块由双向发光连线相连,线上漂浮对话气泡方块,扁平科技插画
服务器与多个客户端保持双向长连接,正是 WebSocket 的意象。

握手:从 HTTP 升级到 WebSocket

WebSocket 不是凭空建立的,它先走一次 HTTP 请求,带上 Upgrade 头,服务器同意后协议切换成 WebSocket。浏览器端用 new WebSocket 一行代码就能发起,服务端需要校验握手请求里的 Sec-WebSocket-Key 并返回正确的响应头。

const ws = new WebSocket("wss://example.com/chat");

ws.onopen = function(){ ws.send("连接已建立"); };
ws.onmessage = function(e){ console.log(e.data); };

服务端框架通常已经封装了握手细节,你只需要定义连接、消息、关闭三个核心事件。握手成功之后,这条 TCP 连接就一直复用,不再每次请求都重新建连。

消息帧与数据格式

WebSocket 通信的最小单位是帧,文本帧、二进制帧、关闭帧各有用途。业务上一般约定一种消息协议:用 JSON 包一层 type 和 data,客户端根据 type 分发处理,服务器广播时也按 type 区分是聊天消息、在线状态还是系统通知。

{"type":"chat","data":{"from":"u1","text":"你好"}}

大消息可以分片发送,压缩可以用扩展协商。实践上保持消息体精简、字段稳定,后续加字段要兼容旧客户端,避免一把梭改格式导致线上抖动。

心跳保活与断线重连

长连接挂在中间代理上,一段时间没有数据就会被认为是死连接被清理,客户端还以为连着。常规做法是定时发 ping 帧,服务器回 pong;连续几次没收到 pong 就判定连接断开,主动关闭并让客户端重连。

const heartbeat = setInterval(function(){
  if (ws.readyState === WebSocket.OPEN) ws.send("ping");
}, 30000);

ws.onclose = function(){ setTimeout(reconnect, 3000); };

重连要带退避:失败后等待时间逐步拉长,避免断网瞬间所有客户端同时重连把服务器打爆。重连成功后还要做状态补偿,把断线期间漏掉的消息补回来。