聊天、行情推送、在线协作……这些功能都要求服务器主动推送数据,而传统 HTTP 是"一问一答"的。WebSocket 在单个 TCP 连接上实现了全双工通信,是实时应用的标配方案。本文讲清原理并给出可运行示例。

1. HTTP 轮询的痛点

在没有 WebSocket 的年代,前端只能定时发请求"问"服务器有没有新数据:

核心矛盾:HTTP 是单向请求-响应模型,服务器无法主动推送,WebSocket 正是为此而生。

2. 握手:从 HTTP 升级而来

WebSocket 连接以一次 HTTP 请求开始,通过 Upgrade 头协商升级协议:

GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

服务器验证 Sec-WebSocket-Key 后返回 101 Switching Protocols,连接升级成功。此后双方就可以在同一条 TCP 连接上双向收发消息,不再有 HTTP 头部的额外开销。

3. 数据帧格式

升级后传输的不再是 HTTP 报文,而是轻量的 WebSocket 帧,关键字段有:

帧头通常只有 2~14 字节,这是比 HTTP 轮询高效的重要原因。

4. 浏览器端示例

const ws = new WebSocket("wss://echo.websocket.org");

// 连接建立后发送消息
ws.onopen = () => {
  ws.send("你好,服务器!");
};

// 收到服务器消息
ws.onmessage = (event) => {
  console.log("收到:", event.data);
};

// 连接关闭(可在此重连)
ws.onclose = () => {
  console.log("连接已关闭");
};

// 心跳保活,防空闲连接被断开
setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send("ping");
  }
}, 30000);

5. 用 wscat 测试服务器

# 安装 wscat(Node.js 环境)
npm install -g wscat

# 连接公共回声服务器
wscat -c wss://echo.websocket.org

# 连接本地开发服务器
wscat -c ws://localhost:3000

写一个最简单的 Node.js 服务器做实验:

const { WebSocketServer } = require("ws");

const wss = new WebSocketServer({ port: 3000 });

wss.on("connection", (socket) => {
  socket.on("message", (data) => {
    // 收到后原样回给客户端
    socket.send(`echo: ${data}`);
  });
});

6. 生产环境的注意点

💡 学习建议:先用公共 echo 服务器跑通浏览器端,再自己写 Node 服务器,最后给聊天室加上心跳和重连。三步走完,WebSocket 的坑你基本都踩过了。