关于uniapp解析SSE响应数据的处理
通过uniapp开发与大模型对话的微信小程序,并且后端需要通过SSE向小程序返回响应数据。
微信小程序端需要展示响应数据,在这个过程中,数据解析这里踩了不少坑。
uniapp端开发微信小程序时,SSE连接处理的代码如下:
const initSSE2 = () => {console.log(uni.getStorageSync('token'))requestTask = uni.request({url: 'http://127.0.0.1:8889/connect',timeout: 30000,responseType: 'text',method: 'POST',enableChunked: true, //配置这里header: {Accept: 'text/event-stream','Authorization': uni.getStorageSync('token') //自定义请求头信息},responseType: 'arraybuffer',data: {},success: response => {console.log("success:" + JSON.stringify(response))},fail: error => {console.log("error:" + JSON.stringify(error))}})requestTask.onHeadersReceived((res) => {console.log("header:" + JSON.stringify(res.header));});// 这里监听消息requestTask.onChunkReceived((res) => {const uint8Array = new Uint8Array(res.data);let text = String.fromCharCode.apply(null, uint8Array);text = decodeURIComponent(escape(text));// 将后台通过streaming response返回的消息拼接到消息中messages.value[messages.value.length - 1].content += text;})}
后端返回的数据,在小程序端展示后结果如下:
从展示效果看,返回的数据都以“data:”开头,而且数据都发生了换行。经过查询资料,了解到SSE返回的数据以"data:"开头,"\n\n"进行结尾,比如上面返回的数据类似这样的格式:
data:你好\n\n
SSE客户端端打印返回的数据:
requestTask.onChunkReceived((res) => {console.log('响应数据:', res.data)const uint8Array = new Uint8Array(res.data);let text = String.fromCharCode.apply(null, uint8Array);text = decodeURIComponent(escape(text));// 将后台通过streaming response返回的消息拼接到消息中messages.value[messages.value.length - 1].content += text;})
打印内容如下:
其中,"100 97 116 97 58"表示"data:","10 10"表示"\n\n",而且根据响应数据,我们发现SSE客户端是一次处理一批后端响应的数据。
于是修改客户端解析数据的逻辑为:
requestTask.onChunkReceived((res) => {console.log('响应数据:', res.data)const uint8Array = new Uint8Array(res.data);let text = String.fromCharCode.apply(null, uint8Array);text = decodeURIComponent(escape(text));console.log('处理前:', text);let info = text.replace(/data:|\n\n/g, '')console.log('处理后:', info)// 将后台通过streaming response返回的消息拼接到消息中messages.value[messages.value.length - 1].content += info;})
其中通过正则表达式替换所有的"data:"和"\n\n"。替换后,展示效果如下:
但是根据后端打印的信息,在"回答:"后面是有换行的,后端输出内容:
这是由于后端返回大模型响应的数据时,需要换行的数据中间也使用了"\n\n",这就和SSE的数据格式产生了冲突。于是我们修改后端返回数据的代码,将"\n\n"替换为"\n":
前后端处理完成后,最终格式如下: