WebSocket 实时通信实战

HTTP 是请求-响应模式,服务端无法主动推消息。聊天、实时股价、在线协作用的都是 WebSocket:一条 TCP 连接,双向实时通信。

WebSocket 配图:蓝色背景上两个端点节点之间双向流动数据流与脉搏信号,扁平科技插画
WebSocket:一条连接,双向实时

一、为什么需要 WebSocket

HTTP 是无状态请求-响应模型:客户端发请求,服务端回响应,然后连接断开。服务端无法主动推送消息。要做实时聊天、股票行情、在线协作,要么轮询(浪费带宽),要么用 WebSocket(一次握手,持续双向通信)。

方案方向延迟开销
轮询客户端拉高大量空请求
长轮询客户端拉中连接挂起
WebSocket双向极低单连接长驻

二、浏览器客户端

// 建立连接
const ws = new WebSocket("wss://api.example.com/ws");

// 连接打开
ws.onopen = () => {
  console.log("连接已建立");
  ws.send(JSON.stringify({ type: "join", room: "chat-1" }));
};

// 收到消息
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("收到消息:", data);
};

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

// 错误处理
ws.onerror = (error) => {
  console.error("WebSocket 错误:", error);
};
协议前缀:ws:// 是明文连接,wss:// 是加密连接(类似 https)。生产环境必须用 wss。

三、Node.js 服务端

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

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

wss.on("connection", (ws) => {
  console.log("新客户端连接");

  ws.on("message", (data) => {
    const msg = JSON.parse(data);
    console.log("收到:", msg);

    // 广播给所有客户端
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({ type: "broadcast", data: msg }));
      }
    });
  });

  ws.on("close", () => {
    console.log("客户端断开");
  });
});

四、心跳与重连

// 客户端心跳:每 30 秒发 ping
setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: "ping" }));
  }
}, 30000);

// 断线自动重连
function connect() {
  const ws = new WebSocket("wss://api.example.com/ws");
  ws.onclose = () => {
    setTimeout(connect, 3000);  // 3 秒后重连
  };
  return ws;
}
let ws = connect();

五、实战:简易聊天室

<input id="msgInput" type="text" placeholder="输入消息">
<button onclick="sendMessage()">发送</button>
<div id="chatBox"></div>

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

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  const div = document.createElement("div");
  div.textContent = data.user + ": " + data.text;
  document.getElementById("chatBox").appendChild(div);
};

function sendMessage() {
  const input = document.getElementById("msgInput");
  ws.send(JSON.stringify({
    user: "小明",
    text: input.value
  }));
  input.value = "";
}
</script>

六、常见坑

第一,连接断开要自动重连,网络抖动很常见。第二,消息要加类型字段,客户端才能区分不同业务消息。第三,服务端要做心跳检测,踢掉僵尸连接。第四,nginx 反向代理要配 Upgrade 和 Connection 头,否则 WebSocket 握手失败。

七、总结

WebSocket 三步:浏览器 new WebSocket() 建立连接、服务端监听 connection 和 message、双向收发 JSON 消息。记住心跳保活 + 断线重连,生产环境用 wss 加密连接。