💡如何使用SSE通信(Event-stream)

我想通过这篇文章,以最简单的方式给大家讲解 SSE(event-stream)通信。

前后端均使用 js 来编写简单代码

后端代码:

需要安装 express:

shell 复制代码
pnpm i express

index.js:

javascript 复制代码
const express = require("express");
const app = express();
const PORT = 3000;

// 处理 SSE 连接
app.get("/events", (req, res) => {
	// 设置必要的 HTTP 头
	res.setHeader("Content-Type", "text/event-stream");
	res.setHeader("Cache-Control", "no-cache");
	res.setHeader("Connection", "keep-alive");

	// 允许跨域(如果需要)
	res.setHeader("Access-Control-Allow-Origin", "*");

	// 发送初始连接确认
	res.write("retry: 10000\n\n");

	// 定时发送消息(示例)
	const sendEvent = (data, id) => {
		res.write(`id: ${id}\n`);
		res.write(`data: ${JSON.stringify(data)}\n\n`);
	};

	let messageId = 0;
	const intervalId = setInterval(() => {
		const data = {
			message: `这是第 ${messageId} 条消息`,
			timestamp: new Date(),
		};
		sendEvent("hello", messageId++);
	}, 3000); // 每3秒发送一次

	// 监听客户端关闭连接
	req.on("close", () => {
		clearInterval(intervalId);
		res.end();
	});
});

app.listen(PORT, () => {
	console.log(`服务器正在运行在 http://localhost:${PORT}`);
});

为了方便测试,允许所有域名访问res.setHeader("Access-Control-Allow-Origin", "*")

代码很简单:

  1. 首先发送了 retry: 10000\n\n,表示意外断开了,重新连接的延迟时间。这里是 10s。如果不发送retry,chrome 会默认 5s
  2. 每隔三秒向浏览器发送消息,虽然调用了两次 write,但也是发送一条消息。
  3. 当客户端主动关闭连接后,会清除定时器

前端代码:

index.html:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>SSE 示例</title>
  </head>
  <body>
    <h1>服务器发送的消息:</h1>
    <ul id="messages"></ul>

    <script>
      const eventSource = new EventSource("http://localhost:3000/events");

      eventSource.onmessage = function (event) {
        console.log("event", event);
        const data = JSON.parse(event.data);
        const li = document.createElement("li");
        li.textContent = `[${new Date(
          data.timestamp
        ).toLocaleTimeString()}] ${data.message}`;
        document.getElementById("messages").appendChild(li);
      };

      eventSource.onerror = function (err) {
        console.error("EventSource 失败:", err);
        eventSource.close();
      };
    </script>
  </body>
</html>

启动前后端:

后端:

shell 复制代码
node index.js

前端:

shell 复制代码
http-server index.html

效果:

前端每收到一条消息,就会在页面上输出。同时在 network 的控制面板,也可以看到 eventStream 的消息流。

拓展:

测试完毕。上面就是SSE通信最基础的用法。

下面深入讲讲 SSE通信 的用法:

event-stream 的每条消息都是以\n\n作为分割符的

上面后端代码中,第二次调用 write 时,消息末尾是\n\n, 所以连同前一个 write的内容,视为一条消息。

消息格式:key: '...'\n 。这样的格式视为一个键值对

js 复制代码
res.write('key: content');

其中content,只允许是字符串。如果想向浏览器发送 json,务必先转成字符串。

下面着重讲讲 key

目前允许的 key 只有三种:ideventdata,这三个 key 对应着下面event-stream中的 IdTypeData

在一条消息中,其中只有 data 不能缺失。其他的两个 key 都可以缺失。

id 在网络重连的时候很有用,如果缺失了 id,不影响浏览器接收消息。

event 指定了消息的 Type,如果 event 缺失,那么 Type 默认是 message,如果指定了其他值,比如man,效果就是下面这样:

javascript 复制代码
res.write(`event: man\n`);

这个时候,前端接收消息就不能使用:

javascript 复制代码
eventSource.onmessage = function (event) {
  const data = JSON.parse(event.data);
  ...
};

而是要:

javascript 复制代码
eventSource.addEventListener("man", (event) => {
  const message = JSON.parse(event.data).message;
});

没错!Type 可以用来标识消息类型,就好像触发了不同的事件。

如果我想将 key 设置为 name,会发生什么?答案是什么也不会发生,SSE 协议会忽略除上面三种之外的所有自定义 key!!

字段类型 客户端是否处理 解决方案
<font style="color:rgba(0, 0, 0, 0.86);">data</font> ✅ 解析为 <font style="color:rgba(0, 0, 0, 0.86);">event.data</font> 直接使用 <font style="color:rgba(0, 0, 0, 0.86);">data</font>
<font style="color:rgba(0, 0, 0, 0.86);">event</font> ✅ 触发特定监听事件 定义 <font style="color:rgba(0, 0, 0, 0.86);">event</font> + 监听对应事件
<font style="color:rgba(0, 0, 0, 0.86);">id</font>/<font style="color:rgba(0, 0, 0, 0.86);">retry</font> ✅ 用于连接管理 按需使用
自定义字段 完全忽略

总结

这篇文章讲了 SSE 通信的简单用法,并且拓展讲了 SSEkey 使用时,要注意的点。大家可以在本地多尝试,加深印象

相关推荐
Cobyte11 分钟前
17. Vue3 业务组件库按需加载的实现原理
前端·javascript·vue.js
谢尔登20 分钟前
原型理解从入门到精通
开发语言·javascript·原型模式
粥里有勺糖23 分钟前
视野修炼-技术周刊第127期 | Valdi
前端·javascript·github
码上成长1 小时前
Vue Router 3 升级 4:写法、坑点、兼容一次讲透
前端·javascript·vue.js
yunxi_051 小时前
分布式文件服务实战稿:从本地存储到对象存储的架构升级
后端·面试
Chan162 小时前
【 Java八股文面试 | Redis篇 缓存问题、持久化、分布式锁 】
java·数据库·redis·后端·spring·缓存·面试
qq_398586542 小时前
浏览器中内嵌一个浏览器
前端·javascript·css·css3
Eloudy2 小时前
节点内 cuda GPU 之间 P2P IPC 通信的硬件机制参考
网络协议·p2p
atsec2 小时前
atsec完成Newland NPT的P2PE PA评估
服务器·网络协议·npt·p2pe
*小雪3 小时前
uniapp写H5授权登录及分享,返回到目标页面
开发语言·javascript·uni-app