前端处理流式数据
前言
本篇文章为笔者开发过程中总结的关于前端处理后端流式接口返回的流式数据
示例
此处以仿gpt对话形式的发送消息函数为例,本次对话为一个包含提问和回答对象的数组
js
async send() {
// 生成新的对话框,并将其id赋值给Tid
const Tid = this.messageIdCounter++
// 复制Vue组件中的一些变量到本地变量
// let _store = this.$store
// 本次对话为一个包含提问和回答对象的数组
let _Message = this.allMessages
// 去除用户输入两端的空格(用作参数)
this.userInput1 = this.userInput.trim()
// 检查用户输入是否非空
if (this.userInput.trim() !== '') {
// 添加用户消息到对话中
this.allMessages.push({
id: this.messageIdCounter++,
type: 'user',
content: this.userInput.trim()
});
// 添加回答框到对话中
this.allMessages.push({
id: Tid,
type: 'chatbot',
content: ''
});
// 构建API请求的URL
const url = '你的后端api'
// 构建API请求的初始化参数
const init = {
method: 'post',
headers: {
'Content-Type': 'application/json',
// 后端所需头
},
body: JSON.stringify({
// 后端所需参数
}),
}
try {
// 发起异步网络请求
const response = await fetch(url, init);
// 检查网络响应是否成功
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// 获取响应体的数据读取器
const reader = response.body.getReader();
// 创建用于解码文本的解码器
const decoder = new TextDecoder('utf-8');
// 创建一个可读流
const stream = new ReadableStream({
async start(controller) {
while (true) {
// 从数据读取器中读取数据
const { done, value } = await reader.read();
// 如果读取完成,关闭控制器并退出循环
if (done) {
controller.close();
break;
}
// 解码值并将其附加到指定ID的消息内容中
const match = decoder.decode(value, { stream: true });
if (match) {
// 此处以String拼接方式给对应的回答对象的内容拼接流式数据
_Message[Tid].content = _Message[Tid].content + match + ''
// 更新 Vuex 中的 streamingData 状态
// _store.commit('updateStreamingData', dataValue);
} else {
// _store.commit('updateStreamingData', decoder.decode(value, { stream: true }));
}
}
},
});
// 输出一条日志,表示流数据已接收完毕
console.log('Full data');
} catch (error) {
// 捕获并打印任何网络请求错误
console.error('Fetch error:', error);
}
// 清空用户输入
this.userInput = '';
}
// 打印所有消息
console.log(this.allMessages)
},
流程说明
-
生成新的对话框: 通过递增 messageIdCounter 变量,生成新的对话框的 ID,并将其赋值给 Tid 变量。
-
复制变量: 复制 Vue 组件中的一些变量到本地变量 _Message。
-
处理用户输入: 去除用户输入两端的空格,将处理后的用户输入保存在 userInput1 变量中。
-
检查用户输入非空: 如果用户输入不为空,执行以下操作:
-
添加用户消息: 向对话中添加用户输入的消息,包括消息的 ID、类型为 'user',以及去除两端空格后的内容。
-
添加聊天机器人回答框: 向对话中添加一个新的聊天机器人回答框,包括消息的 ID、类型为 'chatbot',初始内容为空。
-
构建API请求: 构建发送到后端的 API 请求的 URL 和初始化参数。
-
发起网络请求: 使用 fetch 函数发起异步网络请求,等待响应。
-
处理网络响应: 如果网络响应不成功,抛出错误。如果成功,获取响应体的数据读取器,用于处理流式数据。
-
处理流式数据: 创建一个可读流,循环读取数据,解码数据并将其附加到聊天机器人回答框的内容中。在这里,使用 String 拼接方式,将流式数据追加到聊天机器人回答框的内容。
-
输出日志: 输出一条日志,表示流数据已接收完毕。
-
捕获网络请求错误: 如果发生网络请求错误,捕获错误并输出错误日志。
-
清空用户输入: 无论是否成功,最终都清空用户输入。
-
打印所有消息: 输出当前所有对话框的消息内容,以便进行调试和查看结果。
注意
上方代码中提供了两种前端流式输出数据的方法,其中未被注释的是通过String拼接的方式;被注释掉的是通过更新vuex的方式