工具
ts
// 接受参数
export interface SSEChatParams {
url: string,// sse 连接
onmessage: (event: MessageEvent) => void,// 处理消息的函数
onopen: () => void,// 建立连接触发的事件
finallyHandler: () => void,// 相当于 try_finally 中的 finally 部分,不管出现异常或者关闭必然会执行的代码块
}
class SSEService {
private eventSource: EventSource | null = null;
private finallyHandler: (() => void) | undefined;
// 建立连接
connect(sseChatParams: SSEChatParams) {
this.finallyHandler = sseChatParams.finallyHandler;
this.eventSource = new EventSource(sseChatParams.url);
if (sseChatParams.onopen != null) {
this.eventSource.onopen = sseChatParams.onopen;
}else{
this.eventSource.onopen = () => {
console.log('SSE 连接已开启');
};
}
if (sseChatParams.onmessage != null) {
this.eventSource.onmessage = sseChatParams.onmessage;
} else {
this.eventSource.onmessage = (event) => {
console.log('收到消息:', event.data);
};
}
this.eventSource.onerror = (error) => {
if (this.eventSource?.readyState === EventSource.CLOSED) {
console.log("SSE 连接已关闭");
} else {
console.error("SSE 错误:", error);
}
sseChatParams.finallyHandler();
};
}
// 关闭连接
disconnect() {
if (this.eventSource) {
this.eventSource.close();
console.log("关闭 sse 连接")
if (this.finallyHandler != null) {
this.finallyHandler();
}
}
}
}
export const sseService = new SSEService();
使用
我在我代码中是这样使用的,就这么简单
ts
const onopen = () => {
console.log("建立无敌 sse 连接成功")
}
// 建立连接
let sseChatParams: SSEChatParams = {
onopen,
url: import.meta.env.VITE_GLOB_API_URL + 'sse/createConnect?clientId=' + userStore.getSseClientId(),
onmessage: (event: MessageEvent) => {
// 收到消息
console.log('收到消息xsssx:', event.data);
let chunk = event.data;
if (chunk === '[DONE]') {
sseService.disconnect()
state.imageList = []
chatGuide(chatStore.activeChatId).then(resp => {
chatGuideList.value = resp.data.guideList
scrollViewBottom()
})
return
}
chunk = JSON.parse(chunk)
if (chunk.type === 'error') {
errorText = chunk.content
console.log("errorText", errorText);
updateChatData(errorText)
return;
}
chunk = chunk.content;
if (!chunk) {
return;
}
lastText = lastText + chunk
// 更新聊天数据源中的对话
updateChatData(lastText)
},
finallyHandler: () => {
console.log("finallyHandler操作")
sessionStatus.value = 0
inputDisabled.value = false
dataSources.value[dataSources.value.length - 1].loading = false
loading.value = false
if (!isMobile.value) {
// 聚焦输入框
inputRef.value?.focus()
}
}
};
sseService.connect(sseChatParams)
另外你可能还需要增加一下关闭触发时机
javascript
// 当组件从 DOM 中卸载前执行的操作
onUnmounted(() => {
sseService.disconnect()
})
这里需要提一嘴,关于 sse 中的 onopen 触发时机
当你和服务器建立 sse 连接的时候,如果后端没有通过 sse 返回给你消息的话,那么前端浏览器大概率是不会触发 onopen
事件。
所以当与后端建立连接后要注意咯~
最后介绍一下自己的网站术士 AI:术士AI 2.0 (shushiai.com)
有兴趣用用玩玩,最好也支持一下,谢谢