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();