SSE原理及实现流程

331 阅读1分钟

SSE 是一种从服务端到客户端单向的消息(通信)处理方式,它允许服务器主动向客户端推送实时更新。用来处理的场景一般是,服务器到客户端的实时数据推送。一般具备以下几个特点:

  • 单向性:SSE 只能从服务端传递数据到客户端,不能从客户端传递数据到服务端
  • 简单易用:客户端和服务器端的实现都很简单,易于集成和使用。
  • 数据类型单一:仅用来传输文本数据,不适合传输图片,二进制等文件
  • 基于 HTTP:SSE 使用的是 HTTP 协议通过设置 Content-Type: text/event-stream 来实现的,不需要其他的协议或库支持

功能实现

服务端(nodejs)

对于nodejs实现SSE服务,一般通过定时器加设置Content-Type: text/event-stream 来实现,具体实现流程:

  • 启动服务:启动一个nodejs的服务,可以通过常用的框架express来实现
  • 定义路由:定义一个前端请求的路由地址sse
  • 设置头部:设置返回头部为Content-Type: text/event-stream,设置连接方式为keep-alive
  • 定时返回:通过setInterval定时返回数据到前端,直至数据处理完成。
const express = require("express");
const app = express();


app.use("/sse", (req, res, next) => {
  let number = 0;
  //设置头部
  const requestId = Date.now();
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");

  //定义定时器
  const intervalId = setInterval(() => {
     ***
    const data = ***;
    res.write(`data: ${JSON.stringify(data)}\n\n`);
    //完成时关闭
    clearInterval(intervalId);
    res.end();
  }, 2000);
  //监听客户端关闭请求
  req.on("close", () => {
    console.log("--------- close connect --------");
    clearInterval(intervalId);
    res.end();
  });
});

app.listen(3001, () => {
  console.log("sever is starting!");
});

客户端(web)

web 端提供了实现 SSE 的接口 EventSource,通过 EventSource 我们能简单的实现其与 SSE 的通信,实现流程如下:

  • 创建 EventSource 实例:连接服务端的 SSE 端点
  • 监听消息:EventSource 实现原理是通过事件机制,监听服务端的消息来实现前端实时更新
  • 异常处理:在监听正常消息的同时我们也需要监听服务端异常,如果有异常返回则需要进行相关处理
  • 关闭连接:当服务端标记消息推送完成时,客户端需要关闭连接。
 const sse = new EventSource("/sse");

 sse.addEventListener('message', (event) => {
    console.log('event: ', event.data);
    //完成时需要关闭连接
    sse.close();
 });

 sse.onerror = (error) => {
  console.error('Error:', error);
 };

自定义事件

EventSource 除了以上几个事件监听外,还可以自定义事件,服务端按照对应的规则返回时 EventSource 可以监听到

  • 使用 addEventListener 为自定义事件设置处理器。
const sse = new EventSource("/sse");
  sse.addEventListener('type', (event) => {
      ****
 });

服务端新增事件,数据结构一般为:event: ** data: **

  • 设置发送事件消息,包括事件类型 (event)、数据 (data)、事件 ID (id) 和重新连接时间 (retry)。
  • 发送不同类型的事件,包括默认事件、greeting 事件和 custom 事件。
  • 当请求关闭时,清除定时器并结束响应。
    //定义定时器
    const intervalId = setInterval(() => {
        ***
        res.write(`event: ${type}\n`);
        res.write(`data: ${JSON.stringify(data)}\n\n`);
        ***
    }, 2000);

    //完成时关闭
    clearInterval(intervalId);
    res.end();