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

相关推荐
小小小小宇4 小时前
前端并发控制管理
前端
小小小小宇5 小时前
前端 WebSocket 笔记
前端
小小小小宇6 小时前
前端visibilitychange事件
前端
小小小小宇6 小时前
前端Loader笔记
前端
烛阴7 小时前
从0到1掌握盒子模型:精准控制网页布局的秘诀
前端·javascript·css
前端工作日常11 小时前
我理解的`npm pack` 和 `npm install <local-path>`
前端
李剑一11 小时前
说个多年老前端都不知道的标签正确玩法——q标签
前端
嘉小华11 小时前
大白话讲解 Android屏幕适配相关概念(dp、px 和 dpi)
前端
姑苏洛言11 小时前
在开发跑腿小程序集成地图时,遇到的坑,MapContext.includePoints(Object object)接口无效在组件中使用无效?
前端