前端SSE笔记

前端 Server-Sent Events (SSE) 是一种允许服务器向客户端单向推送更新的技术。与 WebSocket 相比,SSE 更加轻量,基于 HTTP 协议,并且专注于服务器到客户端的数据流。它非常适合那些只需要从服务器接收实时更新的场景,例如新闻推送、股票行情、体育赛事比分、进度条更新等。

SSE 的基本使用

SSE 主要通过浏览器内置的 EventSource API 来实现。

  1. 创建 EventSource 实例:

    js 复制代码
    const eventSource = new EventSource('http://localhost:3000/events');
    // 如果是跨域请求,服务器需要设置 CORS 头
    // const eventSource = new EventSource('http://api.example.com/stream');
    • EventSource 构造函数接收一个 URL 参数,指向服务器端提供 SSE 流的接口。
  2. 事件监听:
    EventSource 实例会触发以下事件:

    • onopen:连接成功建立时触发。
    • onmessage:接收到服务器发送的无类型 消息时触发(即服务器端没有指定 event: 字段的消息)。event.data 包含接收到的数据。
    • onerror:发生错误时触发(例如连接中断、网络错误等)。
    • 自定义事件:如果服务器发送了带有 event: 字段的消息,你可以通过 addEventListener() 监听该自定义事件。
  3. 关闭连接:

    使用 close() 方法关闭 SSE 连接。

    js 复制代码
    eventSource.close();

基本使用示例(前端):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE Basic Demo</title>
</head>
<body>
    <h1>Server-Sent Events 演示</h1>
    <div id="messages"></div>
    <button id="closeButton">关闭连接</button>

    <script>
        const messagesDiv = document.getElementById('messages');
        const closeButton = document.getElementById('closeButton');

        // 假设你的 SSE 服务器运行在 http://localhost:3000/events
        // 你需要一个后端服务器来提供 SSE 服务
        const eventSource = new EventSource('http://localhost:3000/events');

        eventSource.onopen = (event) => {
            console.log('SSE 连接已建立!', event);
            messagesDiv.innerHTML += '<p style="color: green;">连接成功!</p>';
        };

        // 监听默认的 'message' 事件 (服务器只发送 data: 字段)
        eventSource.onmessage = (event) => {
            console.log('收到默认消息:', event.data);
            messagesDiv.innerHTML += `<p><strong>默认消息:</strong> ${event.data}</p>`;
        };

        // 监听自定义事件 'stock_update' (服务器发送 event:stock_update)
        eventSource.addEventListener('stock_update', (event) => {
            console.log('收到股票更新:', event.data);
            const stockData = JSON.parse(event.data); // 解析 JSON 字符串
            messagesDiv.innerHTML += `<p style="color: blue;"><strong>股票更新 (${stockData.symbol}):</strong> ${stockData.price}</p>`;
        });

        // 监听自定义事件 'news_feed'
        eventSource.addEventListener('news_feed', (event) => {
            console.log('收到新闻推送:', event.data);
            messagesDiv.innerHTML += `<p style="color: purple;"><strong>新闻:</strong> ${event.data}</p>`;
        });

        eventSource.onerror = (event) => {
            console.error('SSE 错误:', event);
            messagesDiv.innerHTML += '<p style="color: red;">连接错误或已关闭!</p>';
            if (eventSource.readyState === EventSource.CLOSED) {
                console.log('SSE 连接已关闭。');
            }
        };

        closeButton.addEventListener('click', () => {
            eventSource.close();
            messagesDiv.innerHTML += '<p style="color: gray;">连接已手动关闭。</p>';
        });
    </script>
</body>
</html>

服务器端 SSE 响应格式:

服务器端需要将响应的 Content-Type 设置为 text/event-stream。每个事件由一个或多个以 \n 结尾的行组成,事件之间用两个 \n 分隔。

vbnet 复制代码
// 示例服务器端响应
data: 这是第一条消息\n\n

data: 这是第二条消息\n
data: 包含多行数据\n\n

event: stock_update\n
data: {"symbol": "AAPL", "price": 175.50}\n\n

event: news_feed\n
data: 最新新闻头条:前端技术发展迅速!\n\n

id: 123\n
data: 这是一条带ID的消息\n\n

retry: 5000\n // 告诉浏览器如果连接断开,5秒后重试
data: 这是一条设置重试间隔的消息\n\n

SSE 都能传输什么类型的数据?

SSE 传输的数据类型非常简单,它只能传输纯文本字符串

这是因为 SSE 规范定义了消息体中的 data: 字段,其内容就是纯文本。当你通过 event.data 访问接收到的数据时,它总是一个字符串。

尽管只能传输字符串,但你可以通过序列化的方式传输各种复杂的数据结构:

  1. JSON 字符串 (最常见):

    这是传输结构化数据(如对象、数组)最常用的方式。服务器将 JavaScript 对象或数组序列化为 JSON 字符串,客户端接收后使用 JSON.parse() 解析。

    • 服务器发送: data: {"name": "Alice", "age": 30}\n\n
    • 前端接收: JSON.parse(event.data) 得到 { name: "Alice", age: 30 }
  2. CSV 字符串:

    用于传输表格数据或简单列表。

    • 服务器发送: data: value1,value2,value3\n\n
    • 前端接收: event.data.split(',') 得到 ['value1', 'value2', 'value3']
  3. XML 字符串:

    如果你的数据源是 XML 格式,也可以直接传输 XML 字符串,然后在客户端使用 DOMParser 解析。

    • 服务器发送: data: <user><name>Bob</name></user>\n\n
    • 前端接收: new DOMParser().parseFromString(event.data, "text/xml")
  4. Base64 编码的二进制数据:

    虽然 SSE 本身不能直接传输二进制数据,但你可以将二进制数据(如小图片、PDF 等)Base64 编码为字符串,然后作为 data: 字段的值发送。客户端接收后,再进行 Base64 解码。

    • 服务器发送: data: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0EAw\n\n
    • 前端接收: const img = new Image(); img.src = event.data;

总结来说,SSE 传输的原始数据类型永远是字符串。 任何非字符串类型的数据都需要在服务器端被序列化(转换成字符串),然后在客户端被反序列化(从字符串还原)。JSON 是最推荐和最常用的序列化格式,因为它既易于读写,又支持复杂的数据结构。

SSE 的其他特性

  • 自定义事件类型 (event: 字段):
    服务器可以通过 event: 字段指定事件类型。客户端可以通过 eventSource.addEventListener('your_event_type', handler) 来监听特定类型的事件,而不是所有消息都走 onmessage
  • Last Event ID (id: 字段):
    服务器可以为每个事件指定一个 id:。当连接中断并重新连接时,浏览器会自动在 HTTP 请求头中带上 Last-Event-ID 字段,值为上次收到的最后一个事件的 ID。服务器可以利用这个 ID 来判断从何处继续发送事件,实现断点续传。
  • 重试间隔 (retry: 字段):
    服务器可以通过 retry: 字段指定客户端在连接断开后,应该等待多少毫秒再尝试重新连接。

SSE 与 WebSocket 的选择

  • 选择 SSE:

    • 只需要从服务器向客户端单向推送数据。
    • 对实时性要求不是极高,允许少量延迟。
    • 希望实现更简单的协议和更少的服务器资源消耗。
    • 利用 HTTP/2 的多路复用特性。
    • 内置重连机制。
  • 选择 WebSocket:

    • 需要客户端和服务器之间进行双向实时通信
    • 需要传输二进制数据
    • 对实时性要求极高。
    • 需要更复杂的协议和状态管理。

SSE 是一个强大而简单的工具,适用于许多实时更新的场景,特别是在你不需要客户端向服务器发送大量实时数据时。

相关推荐
liliangcsdn2 分钟前
mac mlx大模型框架的安装和使用
java·前端·人工智能·python·macos
CssHero6 分钟前
基于vue3完成领域模型架构建设
前端
PanZonghui9 分钟前
用项目说话:我的React博客构建成果与经验复盘
前端·react.js·typescript
言兴12 分钟前
教你如何理解useContext加上useReducer
前端·javascript·面试
sunbyte15 分钟前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | GoodCheapFast(Good - Cheap - Fast三选二开关)
前端·javascript·css·vue.js·tailwindcss
前端的日常17 分钟前
网页视频录制新技巧,代码实现超简单!
前端
前端的日常18 分钟前
什么是 TypeScript 中的泛型?请给出一个使用泛型的示例。
前端
今禾19 分钟前
一行代码引发的血案:new Array(5) 到底发生了什么?
前端·javascript·算法
ccc101822 分钟前
老师问我localhost和127.0.0.1,有什么区别?
前端
Struggler28129 分钟前
Chrome插件开发
前端