前言

最近有个需求有个搜索接口需要支持流式和静态两种方法,这个接口的查询时间可能很长,完全等结果出来再返回前端对于用户体验不好,于是就想实现持续性返回以提高用户体验。于是学习一下SSE。

什么是SSE

SSE 是指 Server-Sent Events(服务器推送事件),是一种基于 HTTP 的、服务器向客户端单向推送数据的技术。它允许服务器实时发送数据到客户端,而不需要客户端明确地请求。SSE 主要用于实现服务器向客户端的实时更新,比如新闻更新、股票报价、实时监控等场景。
SSE 的优点在于其简单性和易用性,特别适用于那些需要服务器向客户端实时推送信息的场景。虽然它与 WebSocket 相比有一些限制(比如单向通信),但对于一些应用场景而言,SSE 是一个简单而有效的选择。

一些关键特点包括:

  • 单向通信: SSE 使得服务器可以推送实时数据到客户端,但并不支持客户端向服务器发送数据。

  • 基于标准的 HTTP/HTTPS: SSE 使用普通的 HTTP 或 HTTPS 协议。它与 WebSocket 不同,不需要专门的协议,可以通过常规的网络端口进行通信。

  • 事件流: 服务器发送的数据是一系列事件流,每个事件都以一行文本的形式发送,使用特定的格式和字段(如 eventdataid 等),客户端接收到数据后可以解析并处理它们。

  • 自动重连: SSE 具有自动重连机制,当连接中断时,浏览器会尝试重新建立连接,确保持续地接收服务器的事件流。

什么是EventSource

EventSource 是用于接收服务器端发送的服务器推送事件(Server-Sent Events,SSE)的接口。它允许客户端从服务器端获取实时更新,是一种基于 HTTP 的单向通信机制。

创建 EventSource 实例时,可以传入以下参数:

  • URL(字符串): 指定服务器端点的 URL,从中接收 SSE 事件。
  • 配置对象(可选): 包含设置连接的属性,如请求头、withCredentials 等。

EventSource 方法和事件:

  • EventSource 实例属性:

    • onopen 事件连接建立时触发的回调函数。
    • onmessage 接收到来自服务器端的消息时触发的回调函数。
    • onerror 连接出错时触发的回调函数。
  • EventSource 实例方法:

    • close() 手动关闭 SSE 连接。当你想要终止连接时使用。
  • EventSource 实例 readyState 属性:

    • CONNECTING 表示连接正在建立。
    • OPEN 表示连接已经建立。
    • CLOSED 表示连接已经关闭。

创建 EventSource 实例的参数可以包括:

  • URL 字符串: 作为第一个参数传递,是必需的,用来指定发送 SSE 请求的服务器端点。
  • 配置对象(可选): 可以包含 headers(请求头)等属性,例如:
const eventSource = new EventSource('your_server_endpoint', {
    headers: {
        'Authorization': 'Bearer your_token'
        // 请求头其他信息
    },
    withCredentials: true // 是否发送凭据(比如Cookie)
});

eventSource.onopen = (event) => {
    // 连接建立时的操作
};

eventSource.onerror = (error) => {
    // 错误处理
};

eventSource.onmessage = (event) => {
    // 处理接收到的消息 event.data
};

使用示例

当使用 SSE 在前端实现搜索接口的流式展现时,可以创建一个事件流来接收来自服务器的数据,然后实时将数据展示在页面上。这里有一个简单的例子,假设有一个服务器端点 /search 用于接收搜索请求,并以 SSE 的方式返回搜索结果。

服务器端 SSE 设置(Node.js/Express 示例):

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

// 配置接口
app.get('/search', (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    // 模拟搜索结果
    const searchResults = ['Result 1', 'Result 2', 'Result 3', 'Final Result'];

    searchResults.forEach((result, index) => {
        // 模拟延迟以进行演示
        setTimeout(() => {
            res.write(`data: ${result}\n\n`);
            if (index === searchResults.length - 1) {
                res.end(); // 发送所有结果后关闭连接
            }
        }, 2000 * index); // 模拟发送结果,延迟 2 秒

    });
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

这是一个简单的 Express 服务器,当接收到 /search 路径的请求时,会以 SSE 的方式发送模拟的搜索结果。

前端实现:

const eventSource = new EventSource('/search');

// 监听消息
eventSource.onmessage = (event) => {
    const searchResults = document.getElementById('searchResults');
    searchResults.innerHTML += event.data + '<br>'; // 展示数据
};

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

这段前端代码会创建一个 SSE 连接,监听来自服务器的消息,并将它们展示在 ID 为 searchResults 的 HTML 元素中(假设有一个用于展示结果的 div 或其他元素)。

确保页面上有一个元素,比如 <div id="searchResults"></div> 用于展示搜索结果。

这是一个简单的例子,实际场景中需要根据自己的业务逻辑来处理搜索结果并相应地展示在页面上。

EventSource与WebSocket区别

EventSource 和 WebSocket 是两种用于实现实时通信的技术,但在功能和应用场景上有一些明显的区别。

EventSource:

  • 单向通信: EventSource 是服务器向客户端的单向通信,客户端接收来自服务器的事件流。
  • 基于HTTP协议: EventSource 基于标准的 HTTP/HTTPS 协议,使用长轮询或类似的机制,但并不是完全双向的通信。
  • 文本数据传输: 通常用于传输文本数据,如服务器推送的消息或事件。
  • 自动重连: 当连接中断,EventSource 会自动尝试重新连接,不需要手动处理重连。
  • 适用场景: 适用于服务器向客户端单向推送信息,比如实时更新的新闻、股票报价等,但不适合需要客户端与服务器进行双向通信的场景。

WebSocket:

  • 双向通信: WebSocket 提供全双工、双向通信的能力,客户端和服务器之间可以互相发送数据。
  • 独立的协议: WebSocket 使用自己的协议,建立在 TCP 连接之上,允许在同一个连接上进行双向通信。
  • 任意数据传输: 能够传输任意类型的数据,不限于文本,可以是二进制数据。
  • 手动处理重连: 当连接中断,需要在客户端代码中实现重新连接的逻辑。
  • 适用场景: 适用于需要双向实时通信的场景,比如聊天应用、在线游戏等,其中客户端和服务器都需要发送和接收数据。

EventSource 更适用于服务器向客户端的单向通信,而 WebSocket 则适合需要客户端和服务器双向实时通信的场景。选择使用哪种技术取决于你的具体需求和应用场景。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐