WebSocket 实时通信实战
HTTP 是请求-响应模式,服务端无法主动推消息。聊天、实时股价、在线协作用的都是 WebSocket:一条 TCP 连接,双向实时通信。
一、为什么需要 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 加密连接。