使用@microsoft/fetch-event-source未关闭连接导致的问题
2023-04-05

今天清明节,放假一天,碰巧是个下雨天,本来打算早上睡个大懒觉,可是毕竟周三本来应该是工作日,早上8点,生物钟准时叫醒我。

就想着今天继续把网站上接入的聊天机器人完善一下,前几天用event-source小小改造一番,配置SpringSse可以流式获取数据,今天打算加上markdown渲染的功能,开发过程虽然算不上一切顺利,但也好在没什么大问题。

本地测试一切顺利,ok,部署。

万万没想到有个隐藏的bug,就是每次切换页面回来,就会自动发起一次请求,起初以为是UseEffect导致的,排查一番,不是。又以为是event-source的onOpen时间导致的。依然不是。

最终经过摸索发现,之前的请求虽然都完全返回了,但是连接没有断开,然后离开页面会导致连接关闭,再次进入页面就会自动重试。

经过@tqf朋友的评论提醒,离开页面导致的连接断开可以通过设置 openWhenHidden: true来避免

问题找到了,那么就是找到方法,想到只要从client或者server端断开连接即可。去看了看SseEmitter的API发现没有close的方法,再去看看@microsoft/fetch-event-source也没有close方法

最终在@microsoft/fetch-event-source的issue下找到了一个方法
使用AbortController断开连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const abortController = new AbortController();
const signal = abortController.signal;

fetchEventSource(`api/gpt/streamchat`, {
signal: signal, // 传入signal
method: "POST",
body: JSON.stringify({
"message": message,
"id": id,
"isContext": isContext
}),
onmessage(event) {
if (event.data==="[DONE]") {
// 如果server端发送数据结束,断开连接
abortController.abort();
}
},
headers: {
Accept: "text/event-stream",
"Content-Type": "application/json",
}
}).then(res => {
console.log("[fetchEventSource res]", r)
});