关于uniapp解析SSE响应数据的处理

通过uniapp开发与大模型对话的微信小程序,并且后端需要通过SSE向小程序返回响应数据。

微信小程序端需要展示响应数据,在这个过程中,数据解析这里踩了不少坑。

uniapp端开发微信小程序时,SSE连接处理的代码如下:

javascript 复制代码
  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"进行结尾,比如上面返回的数据类似这样的格式:

javascript 复制代码
data:你好\n\n

SSE客户端端打印返回的数据:

javascript 复制代码
        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客户端是一次处理一批后端响应的数据。

于是修改客户端解析数据的逻辑为:

javascript 复制代码
		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":

前后端处理完成后,最终格式如下: