SSE 与 WebSocket 原生实现对比

同一个 Node 服务同时提供静态页面、SSE 推送和 WebSocket 双向通信。打开页面后可以看到服务端定时推送,也可以通过 WebSocket 主动发送消息并接收回显。

SSE 单向推送

连接中
--最近时间
--服务端数据
--SSE 在线数

WebSocket 双向通信

连接中
--最近时间
--服务端数据
--WS 在线数

SSE 实现方式

  • 服务端返回响应头 Content-Type: text/event-stream,保持 HTTP 连接不关闭。
  • 每条消息按 event: namedata: json 输出,并用空行结束。
  • 浏览器使用 new EventSource('/events') 订阅,断线后浏览器会自动重连。
res.write('event: tick\n');
res.write(`data: ${JSON.stringify(data)}\n\n`);

SSE 重点

  • 适合服务端到浏览器的单向推送,例如通知、进度、行情和日志。
  • 需要关闭代理缓冲,示例里使用 X-Accel-Buffering: no
  • 客户端离开时监听 req.close,及时移除连接,避免内存泄漏。

WebSocket 实现方式

  • 服务端监听 HTTP upgrade 事件,计算 Sec-WebSocket-Accept 完成握手。
  • 握手后 TCP 连接会升级成 WebSocket,双方都可以主动发送消息。
  • 示例用原生 Node 编码和解码文本帧,方便看到协议核心过程。
server.on('upgrade', (req, socket) => {
  // 计算 Sec-WebSocket-Accept
  // 写入 101 Switching Protocols
});

WebSocket 重点

  • 适合双向实时交互,例如聊天、协同编辑、游戏和实时控制台。
  • 浏览器发到服务端的帧必须 mask,服务端发到浏览器的帧不需要 mask。
  • 生产环境建议使用成熟库处理分片、心跳、压缩、鉴权和大消息边界。