首页 > 解决方案 > 使用 fetch API 进行流式传输

问题描述

我创建了 .NET Core API,并在其中公开了一个 POST 端点,该端点将响应流式传输到多个块上,其中每个块包含一个 JSON 对象,并且我创建了 Angular 客户端应用程序,该应用程序通过 fetch API 查询该端点:

const response = await fetch(environment.apiUrl + `/Vehicle/ParseVehiclesData`,
{
  method: 'post',
  body: file,
});

const reader = response.body.getReader();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  let res = JSON.parse(new TextDecoder("utf-8").decode(value));
  console.log(res);
}

我的目标是提供一个进度条,其中包含有关他们已经在每个块中从服务器返回的进度的信息,现在我遇到的问题是当连接速度较弱的用户尝试它时会发生一种行为,他们的消费速度每个块的速度小于服务器提要的速度,这会导致浏览器在存在背压时将块合并在一起,因此我解析解码字符串的尝试失败,因为我将尝试解析类似

{"name":"abc","progress":50}{"name":"ab1","progress":100"}

多个 json 对象将附加在一起,没有分隔符,甚至没有断行,所以我正在寻找的是一种解决方案,它可以防止在有背压​​时合并块,或者在最坏的情况下解析 JSON 对象的方法没有分隔符并将它们提供给自定义流或可观察对象,我们将不胜感激有关该主题的任何帮助。

这些是我在搜索时偶然发现的一些文章, InternetSpeed

标签: javascriptc#streamfetch-api

解决方案


您可以定义一个预解析器来按}{分隔符拆分消息(并处理第一个/最后一个条目):

let preParser = (a)=>a.split('}{').map((item,index) => {
       if(a.split('}{').length>1){
          if (index== 0){return item+'}'} // first msg
          else if (index<a.split('}{').length-1){return '{'+item+'}'} // middle msgs
          else {return '{'+item}} // last msg
       else {return a} // no need to do anything if single msg
})

a='{"name":"abc","progress":50}'

b='{"name":"abc","progress":50}{"name":"ab1","progress":100}{"name":"ab2","progress":150}'


console.log('example 1')
preParser(a).forEach(v => console.log(JSON.parse(v)))

console.log('example 2')
preParser(b).forEach(v => console.log(JSON.parse(v)))


推荐阅读