使用EventSource接受后端返回
发表于:2025-04-09 |

前言

最近接 deepseek,之前接 GPT 用的是 websocket 格式,这次接 deepseek 用到了 EventSource 格式,在此记录一下

EventSource 基本概念

EventSource 接口是 web 内容与服务器发送事件通信的接口。

一个 EventSource 实例会对 HTTP 服务器开启一个持久化的连接,以 text/event-stream 格式发送事件,此连接会一直保持开启直到通过调用 EventSource.close() 关闭。

一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个 event 字段,触发的事件与 event 字段的值相同。如果不存在 event 字段,则将触发通用的 message 事件。

与 WebSocket 不同的是,服务器发送事件是单向的。数据消息只能从服务端到发送到客户端(如用户的浏览器)。这使其成为不需要从客户端往服务器发送消息的情况下的最佳选择。例如,对于处理如社交媒体状态更新、消息来源(news feed)或将数据传递到客户端存储机制(如 IndexedDB 或 web 存储)之类的,EventSource 无疑是一个有效方案。

接入

前端要做的其实就是接受流数据,这里我用 fetch 做个 demo 示例,这里的messages就是我的对话内容渲染,后续自然是还有其他如md格式化等的操作,本篇文章就不多阐述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const param = {
message: "xxxx",
};
const requestUrl = "xxxxx";
const response = await fetch(requestUrl, {
method: "POST",
body: JSON.stringify(param),
headers: {
"Content-Type": "application/json",
},
});

const reader = response.body.getReader();
let decoder = new TextDecoder();

function readStream() {
reader
.read()
.then(({ done, value }) => {
if (done) {
return;
}

// 解码并处理新的内容
const chunk = decoder.decode(value);
// 处理每一行数据
const lines = chunk.split("\n");
lines.forEach((line) => {
if (line.startsWith("data:")) {
// 只取 data: 后面的内容
const content = line.slice(5).trim();
if (content) {
// 直接使用最后一条消息
const lastIndex = messages.value.length - 1;
if (lastIndex >= 0) {
// 创建新的消息对象以确保响应式更新
messages.value[lastIndex] = {
...messages.value[lastIndex],
content: messages.value[lastIndex].content + content,
};
}

// 实时更新聊天记录
updateChat(currentChatId.value, {
messages: messages.value,
});
}
}
});

// 继续读取下一块数据
readStream();
})
.catch((error) => {
console.error("读取流数据出错:", error);
});
}

readStream();

结语

本篇文章就到这里,更多内容敬请期待,债见~

上一篇:
微信小程序接受流返回
下一篇:
谷歌地图浅尝试