前端原生以及axio如何接受流式数据(SSE)
fetch
后端使用SSE流式传输,要求前端正确接受这些数据,记录一下解决方法。
tips:流式传输的数据是可以在浏览器开发者工具中的网络中看到的(会有一个EventSource选项卡)
首先的想法是使用浏览器原生的SSE接口,可以自动解析流式数据的事件名,数据等,但是EventSource构造函数不能接受header配置,如果token是放在header中的,就不能使用这个方式。
// 创建一个新的 EventSource 对象,指定 SSE 服务器的 URL
const eventSource = new EventSource('your_sse_server_url');
// 监听 'open' 事件,当与服务器建立连接时触发
eventSource.addEventListener('open', function (event) {
console.log('与服务器的连接已建立');
});
// 监听'message' 事件,当服务器发送新消息时触发
eventSource.addEventListener('message', function (event) {
const data = JSON.parse(event.data); // 如果数据是 JSON 格式,进行解析
console.log('接收到来自服务器的数据:', data);
// 在这里处理接收到的数据,比如更新页面内容等
});
// 监听 'error' 事件,当连接出错时触发
eventSource.addEventListener('error', function (event) {
if (event.target.readyState === EventSource.CLOSED) {
console.log('与服务器的连接已关闭');
} else {
console.error('连接出错:', event);
}
});
查询资料发现fetch支持流式接收数据,示例:
const res=fetch("/api/chat");//直接使用
const reader = res.body.getReader();//获取ReadableStream
const decoder = new TextDecoder(); //将Uint8Array解码
let done = false;
let data = '';
while (!done) {
const { value, done: doneReading } = await reader.read();
done = doneReading;
if (value) {
data += decoder.decode(value, { stream: true });
}
}
注意,decode时需要加上{ stream: true }参数,因为流式传输时,一个汉字/emoji符号会被拆成多个码点,可能正好不在同一块数据中,stream: true可以在下次解码时自动将缓存字节与新数据块开头拼接,保证正确解码。
如果想使用axios,需要在axios.create时使用adapter:"fetch",因为默认的xhr适配器不支持stream,然后在axios.post时配置responseType: 'stream'即可。