fetch获取流式数据相关问题

fetch获取流式数据相关

最近有对接类似于chartGPT回答问题的接口,踩坑记录

获取数据方式不同

fetch请求不同于XMLHttpRequest请求,是一种新的请求方式,返回的数据为Stream数据,返回结果后需要使用方法获取数据

response.text() -- 得到文本字符串

response.json() -- 得到 json 对象

response.blob() -- 得到二进制 blob 对象

response.formData() -- 得到 fromData 表单对象

response.arrayBuffer() -- 得到二进制 arrayBuffer 对象

response.getReader() -- 得到二进制 BufferReader 对象

js 复制代码
fetch("yourUrl",{
    body: JSON.stringify(params)
}).then(res=>{
    return res.Text()
})

抛出错误的方式不同

fetch请求只要获得响应不会抛出错误,可以使用response.ok判断是否请求成功,返回boolean值,200-299返回true。

tsx 复制代码
fetch("yourUrl",{
    body: JSON.stringify(params)
}).then(res=>{
    return res.body.Text()
}).catch(err => {
// 只要获得响应就不会抛出错误  
})

fetch返回数据方式不同

接口返回的数据有两种情况,一种是所有的数据收到再统一接收,一种是流式数据,获得字符串为切片数据,会有被截断的情况,需要进行数据的容错处理,而使用postMan得到的数据是处理好的每一条都是正常的切片,所以很容易有自己请求是不是那里没写对错觉

流式数据响应头 respose Header中会有

处理流式数据

我们先看看流式数据是什么样的

tsx 复制代码
// 发送请求
const postMsg = async (data: any) => {
    const res = await fetch("yourUrl", {
        method: "POST",
        headers: {"Content-Type": "application/json",
        },
        body: JSON.stringify(data),
    });
    if (res.status && res.status !== 200){
        return false;
    }
    return res?.body?.getReader();
};

// 正如上图,流式数据会有被截断的情况,需要做一些容错处理
const chunkRef = useRef()
const handleChunkData = (chunk: string) => {
   chunk = chunk.trim();
   // 如果存在上一个切片
   if (chunkRef.current) {
      chunk = chunkRef.current + chunk;
      chunkRef.current = "";
   }

   // 如果存在done,认为是完整切片且是最后一个切片
   if (chunk.includes("[DONE]")) {
      return chunk;
   }

   // 最后一个字符串不为},则默认切片不完整,保存与下次拼接使用(这种方法不严谨,但已经能解决大部分场景的问题)
   if (chunk[chunk.length - 1] !== "}") {
      chunkRef.current = chunk;
   }
   return chunk;
}

//发送请求,分批处理
const getDate = async() => {
    const res = await postMsg(params)
    const decoder = new TextDecoder();
    while(1){
        const {done, value} = await res.read()
        if(done){
           return
        }
        // 拿到当前切片的数据
        const text = decoder.decode(value);
        // 处理切片数据
        const chunk = handleChunkData(text)
        // 判断是否有不完整切片,如果有,合并下一次处理,没有则获取数据
        if(chunkRef.current) continue;
        // 获取可用数据
        const data = JSON.parse(chunk)
        // 你的业务...    
    }
    
    
    // 或者你也可以这么写,MDN官网写法
    // 参考网址 https://developer.mozilla.org/zh-CN/docs/Web/API/Streams_API/Using_readable_streams
   res.read().then(function processText({done, value}) {
      if (done) {
         //  结束递归
         console.log("Stream complete");
         return;
      }

      // 处理你的value

      // 递归调用
      return reader.read().then(processText);
   });
}

部署注意事项

开发完本以为万事大吉,线上却出现问题,项目部署在nginx web服务器上,需要把默认开启的缓存关掉,否则nginx代理会因为http缓存等待数据返回再统一返回给客户端,使用流式数据的目的就达不到,需要添加配置(缓存默认都是打开的,有条件的话,可以考虑,fetch流式请求单独走一个代理,避免影响其他请求数据量大没有缓存造成的影响)

proxy_buffering off;

proxy_http_version 1.1;

proxy_set_header Connection "";

以上就是使用fetch获取流式数据应当注意的一些事项。

相关推荐
y先森26 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy26 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu108301891129 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿2 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡3 小时前
commitlint校验git提交信息
前端
虾球xz3 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇3 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端