Skip to content

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 请求,并设置合适的读取超时。
  • 关闭服务时先停止接收新连接,再通知或关闭现有连接,避免请求直接中断。

参阅

基于 MIT 许可发布