WebSocket 与其他实时技术对比
在构建实时 Web 应用时,开发者面临多种技术选择。本章对比 WebSocket 与其他常见的实时通信技术,帮助你根据实际需求做出合适的选择。
WebSocket vs Server-Sent Events (SSE)
Server-Sent Events(SSE)是一种基于 HTTP 的服务器推送技术,允许服务器向客户端发送单向事件流。它和 WebSocket 是实时通信领域最常见的两种选择。
核心差异
| 特性 | WebSocket | SSE |
|---|---|---|
| 通信方向 | 双向(全双工) | 单向(服务器到客户端) |
| 协议 | WebSocket(ws:// 或 wss://) | HTTP(基于 text/event-stream) |
| 自动重连 | 需要手动实现 | 浏览器内置支持 |
| 连接限制 | 无浏览器限制 | HTTP/1.1 下每域名 6 个 |
| 数据类型 | 文本和二进制 | 仅文本(UTF-8) |
| 消息帧 | 需要自行实现 | 内置消息 ID 和事件类型 |
| HTTP/2 支持 | 不受益 | 完全支持多路复用 |
| 浏览器支持 | 99%+ | 97%+ |
| 复杂度 | 中等 | 较低 |
WebSocket 适用场景
WebSocket 提供真正的全双工通信,适合需要客户端和服务器频繁交互的场景:
即时通讯:聊天应用需要双方都能主动发送消息。
// WebSocket 聊天
const ws = new WebSocket('wss://chat.example.com');
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
displayMessage(message);
};
// 客户端可以随时发送消息
function sendMessage(text) {
ws.send(JSON.stringify({
type: 'message',
content: text,
timestamp: Date.now()
}));
}
协作编辑:在线文档、白板等需要实时同步多方操作。
在线游戏:多人游戏需要低延迟的双向通信。
远程控制:需要实时发送控制指令并接收反馈。
SSE 适用场景
SSE 更简单,适合只需要服务器推送的场景:
实时通知:新闻推送、系统通知、社交动态。
// SSE 接收通知
const eventSource = new EventSource('/api/notifications');
eventSource.onmessage = (event) => {
const notification = JSON.parse(event.data);
showNotification(notification);
};
// 支持命名事件
eventSource.addEventListener('alert', (event) => {
showAlert(JSON.parse(event.data));
});
实时监控:服务器状态、股票行情、日志流。
进度更新:文件上传进度、任务执行状态。
AI 流式输出:LLM token 流式生成。
SSE 服务端实现
SSE 使用标准 HTTP 响应,实现非常简单:
// Node.js Express SSE
app.get('/events', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// 发送数据
const sendEvent = (data) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// 发送命名事件
const sendNamedEvent = (event, data) => {
res.write(`event: ${event}\n`);
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// 发送带 ID 的消息(用于断线重连恢复)
const sendWithId = (id, data) => {
res.write(`id: ${id}\n`);
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// 心跳保持连接
const heartbeat = setInterval(() => {
res.write(': heartbeat\n\n');
}, 30000);
// 清理
req.on('close', () => {
clearInterval(heartbeat);
});
});
SSE 断线重连机制
SSE 的自动重连是其重要优势:
const eventSource = new EventSource('/events');
// 浏览器自动重连,并带上 Last-Event-ID 头部
// 服务器可以根据此 ID 恢复消息流
eventSource.onerror = (event) => {
if (event.target.readyState === EventSource.CLOSED) {
console.log('连接已关闭');
} else if (event.target.readyState === EventSource.CONNECTING) {
console.log('正在重连...');
}
};
服务器可以通过发送 retry 字段设置重连间隔:
retry: 5000
data: 连接已建立
混合使用
在实际项目中,可以同时使用两种技术:
// SSE 用于服务器广播
const broadcasts = new EventSource('/api/broadcasts');
broadcasts.onmessage = (e) => {
showNotification(e.data);
};
// WebSocket 用于交互功能
const chat = new WebSocket('wss://api.example.com/chat');
chat.onmessage = (event) => {
displayMessage(JSON.parse(event.data));
};
// HTTP 用于常规 API 请求
async function updateProfile(data) {
await fetch('/api/profile', {
method: 'PUT',
body: JSON.stringify(data)
});
}
WebSocket vs HTTP 长轮询
长轮询是 WebSocket 普及之前常用的实时通信方案。
工作原理对比
HTTP 长轮询:
WebSocket:
性能对比
| 指标 | HTTP 长轮询 | WebSocket |
|---|---|---|
| 连接开销 | 每次请求重新建立 | 一次握手后保持 |
| 延迟 | 较高(每次请求往返) | 较低(持久连接) |
| 服务器资源 | 较高(频繁创建连接) | 较低 |
| 带宽消耗 | 较高(重复的 HTTP 头) | 较低(轻量帧头) |
| 实时性 | 取决于轮询间隔 | 真正实时 |
| 浏览器支持 | 所有浏览器 | 现代浏览器 |
长轮询示例
// 客户端长轮询
async function longPoll() {
try {
const response = await fetch('/api/poll?lastId=' + lastMessageId);
const messages = await response.json();
messages.forEach(msg => {
displayMessage(msg);
lastMessageId = msg.id;
});
// 立即发起下一次请求
longPoll();
} catch (error) {
// 出错后延迟重试
setTimeout(longPoll, 5000);
}
}
longPoll();
长轮询的主要问题是:
- 每次请求都带有完整的 HTTP 头部
- 服务器需要维护大量等待中的请求
- 消息传递延迟取决于轮询间隔
WebSocket vs WebRTC
WebRTC 主要用于浏览器之间的点对点通信,与 WebSocket 的定位不同。
应用场景对比
| 场景 | WebSocket | WebRTC |
|---|---|---|
| 客户端-服务器通信 | 完美适合 | 不适合 |
| 浏览器间通信 | 需要服务器中转 | 直接 P2P |
| 音视频传输 | 需要自己实现编解码 | 内置支持 |
| 文件传输 | 适合小文件 | 适合大文件 P2P |
| 游戏 | 适合需要服务器的游戏 | 适合 P2P 游戏 |
协作关系
WebSocket 和 WebRTC 经常配合使用:
// WebSocket 用于信令交换
const signaling = new WebSocket('wss://signaling.example.com');
signaling.onmessage = async (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'offer':
// 收到 WebRTC offer
const pc = new RTCPeerConnection();
await pc.setRemoteDescription(data.offer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
signaling.send(JSON.stringify({
type: 'answer',
answer: answer
}));
break;
case 'candidate':
// 收到 ICE candidate
await pc.addIceCandidate(data.candidate);
break;
}
};
WebSocket 负责信令交换,WebRTC 负责实际的媒体和数据传输。
WebSocket vs WebTransport
WebTransport 是新一代的浏览器传输 API,基于 HTTP/3。
WebTransport 特点
WebTransport 提供三种通信模式:
// 检查支持
if ('WebTransport' in window) {
const transport = new WebTransport('https://example.com/transport');
await transport.ready;
// 1. 数据报(不可靠,类似 UDP)
const datagram = transport.datagrams;
const writer = datagram.writable.getWriter();
await writer.write(new Uint8Array([1, 2, 3]));
// 2. 单向流
const stream = await transport.createUnidirectionalStream();
const streamWriter = stream.writable.getWriter();
await streamWriter.write(new Uint8Array([4, 5, 6]));
// 3. 双向流
const bidirectional = await transport.createBidirectionalStream();
// 可读可写
}
对比总结
| 特性 | WebSocket | WebTransport |
|---|---|---|
| 协议 | WebSocket (RFC 6455) | HTTP/3 |
| 可靠性 | 完全可靠 | 可选可靠或不可靠 |
| 多路复用 | 单一消息流(HTTP/2 下可多路复用) | 多个独立流 |
| 背压支持 | 有限(WebSocketStream) | 原生支持 |
| 浏览器支持 | 99%+ | 较新浏览器 |
| 适用场景 | 通用实时通信 | 高性能、多流场景 |
WebTransport 更适合需要多个独立数据流、对延迟敏感的应用,如游戏和直播。
WebSocket 与 HTTP/2/HTTP/3 的演进
WebSocket 协议也在不断演进以适应新的网络环境:
| 协议版本 | 标准 | 连接方式 | 优势 |
|---|---|---|---|
| WebSocket over HTTP/1.1 | RFC 6455 | 独立 TCP 连接 | 广泛支持,稳定可靠 |
| WebSocket over HTTP/2 | RFC 8441 | HTTP/2 流 | 与 HTTP 共享连接,多路复用 |
| WebSocket over HTTP/3 | 草案阶段 | HTTP/3 流 | 更低的连接建立延迟 |
WebSocket over HTTP/2 的改进:RFC 8441 允许 WebSocket 在 HTTP/2 连接上运行,解决了传统 WebSocket 无法与 HTTP/2 共享连接的问题。当页面通过 HTTP/2 加载时,WebSocket 可以使用同一 TCP 连接,减少连接开销。
如何选择
决策流程
需要实时通信?
├── 只需服务器推送?
│ ├── 需要简单实现? → SSE
│ └── 需要二进制数据? → WebSocket
│
├── 需要双向通信?
│ ├── 需要浏览器间 P2P? → WebRTC (+ WebSocket 信令)
│ ├── 需要多个独立流? → WebTransport
│ └── 通用场景? → WebSocket
│
└── 消息频率低或不重要? → HTTP 轮询
场景推荐
| 应用场景 | 推荐技术 | 理由 |
|---|---|---|
| 聊天应用 | WebSocket | 需要双向实时通信 |
| 股票行情 | SSE 或 WebSocket | 单向推送,SSE 更简单 |
| 在线游戏 | WebSocket 或 WebTransport | 低延迟双向通信 |
| 实时通知 | SSE | 单向推送,自动重连 |
| 视频会议 | WebRTC + WebSocket | 音视频 P2P + 信令 |
| 协作编辑 | WebSocket | 双向实时同步 |
| 日志流 | SSE | 单向流式输出 |
| AI 流式输出 | SSE 或 WebSocket | 单向流,SSE 更常见 |
小结
选择实时通信技术时,需要考虑:
- 通信方向:单向推送选 SSE,双向通信选 WebSocket
- 数据类型:二进制数据必须用 WebSocket 或 WebTransport
- 可靠性需求:SSE 自动重连,WebSocket 需要手动实现
- 浏览器兼容:WebSocket 支持最广泛
- 性能需求:高性能场景考虑 WebTransport
实际项目中,多种技术可以共存,根据不同功能选择最合适的方案。例如,SSE 处理通知推送,WebSocket 处理聊天交互,HTTP 处理常规 API 请求。