真实有效:在 UniApp + Vue2 中处理 SSE 数据流
·
H5页面/pc端:@microsoft/fetch-event-source
1. 安装依赖
首先安装必要的依赖:
npm install @microsoft/fetch-event-source
2. 添加代码
sendMessageSSEH5(id, userId, question) {
let that = this;
let len = this.msgList.length;
let str = '';
fetchEventSource('/api/xlx-chat/chatMessage/sendMessageSSE', {
method: 'POST',
headers: this.setHeaders(),
body: JSON.stringify({
id,
userId,
question
}),
onopen(response) {
if (response.ok) {
console.log('SSE连接成功');
} else {
throw new Error('连接失败');
}
},
onmessage(msg) {
// ...原有处理逻辑
let {
data
} = msg;
if (data &&
!data.includes('<br/><br/>tokens') &&
!data.includes('[DONE]')
) {
let parseData = JSON.parse(data);
str += parseData.content;
// 数据更新视图不更新==>解决办法是 $set
that.$set(that.msgList, len, {
role: 'system',
content: str
})
}
},
onerror(err) {
console.error('SSE错误:', err);
// 实现重连逻辑
},
openWhenHidden: true // 即使页面隐藏也保持连接
});
},
微信小程序:uni.request+enableChunked
sendMessageSSEWX(id, userId, question) {
let that = this;
let len = this.msgList.length;
let str = '';
console.log(this.setHeaders());
let requestTask = uni.request({
url: 'https://ai.xuexiluxian.cn/api/xlx-chat/chatMessage/sendMessageSSE',
enableChunked: true, //这个地方需要开启
header: this.setHeaders(), //这里是header
method: 'post',
data: JSON.stringify({
id,
userId,
question
}),
success(res) { //这里的success相当于close==》而且必须写,不写下面的事件用不了
console.log('连接关闭', res);
}
})
requestTask.onHeadersReceived(res => { //等同于 onopen
console.log('连接是否成功', res);
})
requestTask.onChunkReceived(res => { //等同于 onmessage
const arrayBuffer = res.data;
const uint8Array = new Uint8Array(arrayBuffer);
let data = uni.arrayBufferToBase64(uint8Array);
data = new Buffer(data, 'base64');
data = data.toString('utf8');
const lines = data.split('\n\n');
lines.forEach(line => {
if (line.indexOf('{') != -1) {
const dataMatch = line.match(/data:(\{.*\})/);
if (dataMatch && dataMatch[1]) {
const dataString = dataMatch[1];
try {
data = JSON.parse(dataString);
str += data.content;
that.$set(that.msgList, len, {
role: 'system',
content: str
})
} catch (e) {
console.log('解析错误:', e);
}
}
}
})
})
},
APP端:使用 renderjs + @microsoft/fetch-event-source
要在 UniApp (Vue2) 的 App 端处理 Server-Sent Events (SSE) 数据流,可以使用 renderjs 结合 @microsoft/fetch-event-source 库。以下是完整的实现方案:
1. 安装依赖
首先安装必要的依赖:
npm install @microsoft/fetch-event-source
2. 添加代码
<template>
<!-- #ifdef APP -->
<button :props='mergeProps' :change:props='eventSource.renderBeforeSend' v-show='false'>app端的发送</button>
<!-- #endif -->
<button class="send-btn" @click="sendMessage">
<uni-icons type="paperplane" size="20" color="#fff"></uni-icons>
</button>
</template>
<script>
data() {
return {
chatId: '', //会话的id
userInput: '', //初次内容
userId: JSON.parse(uni.getStorageSync('luxian-store')).user.userInfo.userId, //用户id
//返回的消息列表数据
msgList: [],
isSend: true //是否发送消息
}
},
computed: {
mergeProps() {
return {
token: this.token, // 依赖Vuex的token
isSend: this.isSend, // 依赖组件的isSend
msgList: this.msgList, // 依赖组件的msgList
userId: this.userId, // 依赖组件的userId
id: this.chatId // 依赖组件的id
}
}
},
methods: {
// 获取来自renderjs的消息
emits({
str,
len
}) {
this.$set(this.msgList, len, {
role: 'system',
content: str
})
this.isSend = false;
},
}
</script>
<script module='eventSource' lang='renderjs'>
import {
fetchEventSource
} from '@microsoft/fetch-event-source';
export default {
methods: {
renderBeforeSend(nVal) {
let {
isSend
} = nVal;
if (!isSend) return;
this.handleSSE(nVal);
},
handleSSE(nVal) {
let {
token,
msgList,
userId,
id
} = nVal;
let that = this;
let len = msgList.length;
let str = '';
//1. 设置headers
const headers = {
'Content-Type': 'application/json',
}
//2. 传递token
if (token) {
headers['Authorization'] = token;
}
fetchEventSource('https://ai.xuexiluxian.cn/api/xlx-chat/chatMessage/sendMessageSSE', {
method: 'post',
headers,
body: JSON.stringify({
id: id,
userId: userId,
question: msgList.at(-1).content
}),
onopen() {
console.log('sse连接成功');
},
onmessage(msg) {
let {
data
} = msg;
if (data &&
!data.includes('<br/><br/>tokens') &&
!data.includes('[DONE]')
) {
let parseData = JSON.parse(data);
str += parseData.content;
//把render中的str更新到msgList中
that.$ownerInstance.callMethod('emits', {
str,
len
});
}
},
onclose() {
console.log('关闭');
}
})
}
}
}
</script>更多推荐
所有评论(0)