SSE服务器主动推送至浏览器客户端,让你不再需要websocket

发布于:2025-03-31 ⋅ 阅读:(23) ⋅ 点赞:(0)

Server-Sent Events(SSE)是一种服务器向客户端推送实时更新的技术,基于HTTP协议。客户端通过EventSource API来接收事件流,而服务器则保持一个长连接,持续发送数据。这与传统的请求-响应模式不同,允许服务器主动推送数据,而不是等待客户端请求。

客户端通过创建一个EventSource对象,指定服务器的URL。服务器设置特定的HTTP头(如Content-Type: text/event-stream)并保持连接打开。服务器可以周期性或根据事件发送数据,数据格式遵循SSE的规范,每条消息以"data: "开头,后跟数据内容,用两个换行结束。

然后,优缺点分析。优点是简单易用,基于HTTP,兼容性好,适合低频更新。缺点是单向通信,服务器到客户端,不支持客户端发送数据;同时,HTTP协议本身不是为长连接设计的,可能在某些情况下效率不如WebSocket。

适用场景包括实时新闻推送、股票行情更新、日志监控等不需要高频双向通信的场景。而如果应用需要高频通信或双向通信,WebSocket可能更合适。

最后,可能需要提到一些实现细节,比如数据格式、事件类型、重试机制等,以及如何在不同后端语言中实现SSE,比如java、PHP、Node.js等。

1. 工作原理

  • 客户端:通过 JavaScript 的 EventSource API 建立长连接
  • 服务端:设置 Content-Type: text/event-stream 响应头,保持连接持续打开
  • 通信方式:服务器按需发送文本数据流(UTF-8 编码),客户端自动解析

2. 核心优势

  • 轻量级:基于 HTTP 协议,无需复杂握手
  • 自动重连:内置断线重试机制
  • 兼容性佳:所有现代浏览器均支持
  • 简单实现:服务端只需保持长连接并发送文本流

3. 典型应用场景

  • 实时数据看板(如股票行情、系统监控)
  • 日志流实时查看
  • 通知推送系统
  • 协作工具中的实时更新

4. 与 WebSocket 对比

特性 SSE WebSocket
通信方向 单向(服务器→客户端) 双向
协议 HTTP 独立协议
连接数 天然支持多标签页共享 需自行处理多连接
数据格式 文本流 二进制/文本
适用场景 低频更新 高频/双向通信

5. 最佳实践建议

  • 频率控制:建议至少间隔 1 秒发送数据,避免高频触发重绘
  • 数据压缩:使用 gzip 或 deflate 压缩传输内容
  • 错误处理:监听 onerror 事件并实现自动重连逻辑
  • 性能优化:结合 Last-Event-ID 实现断点续传
  • 安全退出:结束时发送空消息或特殊标识(如 data: END)

6. 代码示例

服务端源码

const express = require('express');
const app = express();
const port = 3000;

// 静态文件服务
app.use(express.static('public'));

// SSE路由
app.get('/events', (req, res) => {
  // 设置SSE所需的头信息
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  // 发送初始消息
  res.write('data: Connected to SSE server\n\n');

  // 定时发送消息
  let counter = 0;
  const intervalId = setInterval(() => {
    counter++;
    const data = {
      message: `Server time: ${new Date().toISOString()}`,
      counter: counter
    };
    res.write(`data: ${JSON.stringify(data)}\n\n`);
    
    // 模拟结束条件
    if (counter >= 10) {
      res.write('event: end\ndata: Stream ended\n\n');
      clearInterval(intervalId);
      res.end();
    }
  }, 1000);

  // 客户端断开连接时清理
  req.on('close', () => {
    console.log('Client disconnected');
    clearInterval(intervalId);
    res.end();
  });
});

app.listen(port, () => {
  console.log(`SSE server running at http://localhost:${port}`);
});

客户端H5页面端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE Demo</title>
</head>
<body>
    <h1>Server-Sent Events Demo</h1>
    <div id="events"></div>

    <script>
        const eventSource = new EventSource('/events');
        const eventsDiv = document.getElementById('events');
        
        // 监听默认消息事件
        eventSource.onmessage = function(e) {
            const data = JSON.parse(e.data);
            const p = document.createElement('p');
            p.textContent = `${data.message} (Count: ${data.counter})`;
            eventsDiv.appendChild(p);
        };
        
        // 监听自定义事件
        eventSource.addEventListener('end', function(e) {
            const p = document.createElement('p');
            p.textContent = `Event: ${e.type}, Data: ${e.data}`;
            eventsDiv.appendChild(p);
            eventSource.close();
            console.log('EventSource closed');
        });
        
        // 错误处理
        eventSource.onerror = function(e) {
            console.error('EventSource failed:', e);
            eventSource.close();
        };
    </script>
</body>
</html>

7. 注意事项

  1. 连接管理:确保在客户端断开连接时清理定时器和资源

  2. 重连机制:SSE客户端会自动尝试重新连接

  3. CORS:如果客户端和服务器不同源,需要设置CORS头

  4. 性能考虑:对于大量客户端连接,考虑使用专门的解决方案如Redis PUB/SUB

  5. 浏览器支持:大多数现代浏览器都支持SSE,但不包括IE

SSE 适用于大多数实时性要求不高的场景,如实时通知、股票行情、新闻推送等。其简洁性和兼容性使其成为轻量级实时通信的首选方案。对于需要双向通信或高频更新的场景,建议考虑 WebSocket 技术。