主题
WebSocket 服务端(Node.js)
ws 是 Node.js 常用的 WebSocket 库。它与 Socket.IO 协议不兼容;Socket.IO 客户端不能直接连接 ws 服务端。
安装
bash
pnpm add ws挂载到 HTTP 服务
js
import http from 'node:http'
import { WebSocketServer, WebSocket } from 'ws'
const server = http.createServer()
const wss = new WebSocketServer({ server, path: '/ws' })
wss.on('connection', (socket, request) => {
console.log('connected:', request.socket.remoteAddress)
socket.on('message', (raw, isBinary) => {
if (isBinary) return
const message = JSON.parse(raw.toString())
const payload = JSON.stringify({ type: 'echo', data: message })
for (const client of wss.clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(payload)
}
}
})
socket.on('error', (error) => console.error('socket error:', error))
})
server.listen(3000)生产服务应在 connection 前完成身份校验与 Origin 校验。不要仅因为客户端传入用户 ID 就信任其身份。
心跳与失活连接
ws 支持协议级 ping/pong。服务端定时探测,未响应的连接应终止,避免网络已断开但连接长期占用资源。
js
function heartbeat() {
this.isAlive = true
}
wss.on('connection', (socket) => {
socket.isAlive = true
socket.on('pong', heartbeat)
})
const interval = setInterval(() => {
for (const socket of wss.clients) {
if (!socket.isAlive) {
socket.terminate()
continue
}
socket.isAlive = false
socket.ping()
}
}, 30_000)
wss.on('close', () => clearInterval(interval))生产注意
- 限制单条消息大小、连接数和发送频率,解析 JSON 前先处理异常输入。
- 广播前检查
readyState;慢客户端会造成积压,应结合bufferedAmount进行背压控制或断开连接。 - 多实例部署时,连接仅存在于本机。跨实例广播需要 Redis 等消息总线,负载均衡还应启用 WebSocket 转发与会话粘性。
- 反向代理需要正确转发 HTTP Upgrade 请求,并设置合适的读取超时。
- 关闭服务时先停止接收新连接,再通知或关闭现有连接,避免请求直接中断。
