在现代 Web 开发中,实时推送技术的应用场景(如实时数据大屏、消息通知、聊天功能等)越来越广泛。本文将从技术原理、实现方案对比、实际应用三个维度,深入解析三种主流实时推送技术:轮询、WebSocket 和 SSE(Server-Sent Events),帮助开发者根据业务场景选择最合适的方案。
1. 轮询(Polling)
原理:客户端定时向服务端发起请求,服务端返回最新数据。
实现方式:通过 setInterval
或 setTimeout
定时发送 HTTP 请求。
缺点与局限性
适用场景:仅在浏览器不支持 WebSocket 或 SSE 的极端情况下使用(如旧版 IE 浏览器)。
2. WebSocket
原理:基于 TCP 的全双工通信协议,服务端与客户端可双向实时传输数据。
协议:ws://
(非加密)或 wss://
(加密)。
核心优势
技术挑战
适用场景:需要双向实时通信的场景,如:
3. Server-Sent Events(SSE)
原理:基于 HTTP/1.1 的单向流式传输协议,服务端可主动推送数据到客户端。
协议:通过标准 HTTP 协议实现,无需额外协议支持。
核心优势
局限性
适用场景:服务端单向推送的场景,如:
维度 | WebSocket | SSE | 轮询 |
---|---|---|---|
通信方向 | 双向 | 单向(服务端→客户端) | 单向(客户端→服务端) |
协议复杂度 | 高(需处理握手/数据帧) | 低(基于 HTTP) | 低(简单 HTTP 请求) |
实时性 | 高 | 高(依赖服务端推送频率) | 中(受轮询间隔限制) |
开发成本 | 高(需处理连接管理) | 低(浏览器原生支持) | 极低(简单 HTTP 请求) |
服务器负载 | 高(保持 TCP 连接) | 中(长连接占用资源较少) | 低(按需发起请求) |
断线重连 | 需手动实现 | 浏览器自动重连 | 客户端需手动重试 |
适用场景 | 聊天、游戏、实时协作 | 数据监控、消息通知 | 无其他选择时的降级方案 |
选型建议:
<!DOCTYPE html>
<html>
<head>
<title>SSE Demo</title>
</head>
<body>
<ul id="messages"></ul>
<script>
// 检查浏览器是否支持 **SSE**
if (!window.EventSource) {
alert("您的浏览器不支持 **SSE**!");
throw new Error("SSE 不支持");
}
const source = new EventSource('/sse'); // 连接服务端
// 监听连接打开事件
source.onopen = () => {
console.log("已连接到服务端");
};
// 监听消息事件
source.onmessage = (event) => {
const data = JSON.parse(event.data);
const li = document.createElement('li');
li.textContent = `时间:${data.time}`;
document.getElementById('messages').appendChild(li);
};
// 监听错误事件
source.onerror = (err) => {
console.error("连接错误", err);
source.close();
};
</script>
</body>
</html>
const express = require('express');
const app = express();
const port = 3000;
// 跨域配置
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Content-Type', 'text/event-stream');
res.header('Cache-Control', 'no-cache');
res.header('Connection', 'keep-alive');
next();
});
// **SSE** 接口
app.get('/sse', (req, res) => {
// 每秒推送当前时间
const interval = setInterval(() => {
const time = new Date().toLocaleTimeString();
res.write(`data: ${JSON.stringify({ time })}\n\n`);
}, 1000);
// 处理客户端断开
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
app.listen(port, () => {
console.log(`服务已启动,访问 http://localhost:${port}`);
});
浏览器兼容性:
WebSocket
构造函数检测)。服务端实现:
data: ...
格式,每条消息以 \n\n
分隔。性能优化:
通过合理选择 实时推送技术(如 WebSocket 或 SSE),开发者可以高效实现各类实时推送需求,同时兼顾性能与开发成本。