Server-Sent Events (SSE) 指南

1. 什么是 SSE?

Server-Sent Events (SSE) 是一种允许服务器向客户端推送数据的 Web 技术:

  • 它建立在 HTTP 协议之上,是一种单向通信机制(服务器→客户端)
  • 使用持久化的 HTTP 连接实现实时数据推送
  • 数据格式为 UTF-8 编码的文本消息
  • 浏览器原生支持,使用 EventSource API

2. SSE vs 其他实时通信技术

2.1 Client Polling

  • 客户端定期轮询服务器
  • 实现简单但效率低
  • 即使没有更新也会发送请求

2.2 WebSocket

  • 双向通信
  • 需要额外的协议支持
  • 实现相对复杂

2.3 SSE的优势

  • 基于 HTTP,实现简单
  • 自动重连机制
  • 原生事件 ID 跟踪
  • 标准化的消息格式

3. 适用场景

SSE 特别适合以下应用场景:

  • 实时股票行情
  • 体育比分直播
  • 新闻推送
  • 系统通知
  • 物联网数据推送
  • 电商实时信息
  • 监控系统

4. 技术实现

4.1 服务器端实现

服务器需要:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

消息格式:
id: <事件ID>
event: <事件类型>
data: <事件数据>
retry: <重连时间>

4.2 客户端实现

//
const eventSource = new EventSource('http://localhost:3000/events');

// 处理连接打开
eventSource.onopen = (event) => {
    console.log('Connection opened');
};

// 处理消息
eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log('Received:', data);
};

// 处理错误
eventSource.onerror = (error) => {
    console.error('EventSource failed:', error);
    eventSource.close();
};

// 监听自定义事件
eventSource.addEventListener('customEvent', (event) => {
    console.log('Custom event:', event.data);
});

4.3 Node.js SSE 实现示例


// 创建Express应用实例
const app = express();

// SSE(服务器发送事件)端点
app.get('/events', (req, res) => {
    // 设置SSE所需的HTTP头
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    // 每2秒发送一条普通消息
    const timeIntervalId = setInterval(() => {
        const data = {
            time: new Date().toLocaleTimeString(),
            message: 'Server time update'
        };
        res.write(`data: ${JSON.stringify(data)}\n\n`);
    }, 2000);

    // 每5秒发送一条自定义事件消息
    const customIntervalId = setInterval(() => {
        const customData = {
            time: new Date().toLocaleTimeString(),
            message: 'This is a custom event!'
        };
        // 发送带有自定义事件类型的SSE数据
        res.write(`event: customEvent\n`);
        res.write(`data: ${JSON.stringify(customData)}\n\n`);
    }, 5000);

    // 当客户端断开连接时清理所有定时器
    req.on('close', () => {
        clearInterval(timeIntervalId);
        clearInterval(customIntervalId);
    });
});

5. 注意事项与限制

5.1 主要限制

  • 仅支持文本数据(UTF-8),不支持二进制,消息格式必须符合 SSE 规范(如结尾需要 \n\n)
  • 浏览器对同一域名有 TCP 连接数限制(通常为 6-8 个),HTTP1.1每个 SSE 连接会占用一个 TCP 连接,当达到最大连接数时,新的 SSE 连接将被阻塞或失败。可以使用HTTP2.0支持多路复用,单个 TCP 连接可处理多个 SSE 流
  • IE不支持SSE,需要考虑降级方案(如 long polling),主流现代浏览器(Chrome、Firefox、Safari、Edge)都支持

5.2 最佳实践

  • 实现错误处理和重试机制
  • 合理设置超时和重连间隔
  • 考虑服务器负载能力
  • 在需要时正确关闭连接