简体   繁体   English

无法使用 node-fetch 在 json stream 上解析

[英]Fail to parse on a json stream using node-fetch

I run the sample code from node-fetch stream feature.我从node-fetch stream 功能运行示例代码。 Sometime it can successfully parse the chunk, sometimes return error msg SyntaxError: Unexpected token { in JSON at position 312有时它可以成功解析块,有时返回错误消息SyntaxError: Unexpected token { in JSON at position 312

const fetch = require('node-fetch');

async function main() {
  const response = await fetch('https://httpbin.org/stream/3');
  try {
    for await (const chunk of response.body) {
      console.log(JSON.parse(chunk.toString()));
    }
  } catch (err) {
    console.error(err.stack);
  }
}

main()

Anyone know why?有人知道为什么吗? Can I rely on the chunk?我可以依靠大块吗?

By requesting https://httpbin.org/stream/3 , the server sends the data splitting into 3 chunks via stream. The client (in this case your node script) keeps connection with the server and keep receiving the data and splits them into chunks.通过请求https://httpbin.org/stream/3 ,服务器通过 stream 发送分成 3 个块的数据。客户端(在本例中是您的节点脚本)保持与服务器的连接并继续接收数据并将它们分成块。

The node-fetch simply splits data into chunks every time when a single asynchronous task is completed as you can see here: line 199 of body.js .每次完成单个异步任务时, node-fetch只是将数据分成块,如您在此处所见: body.js 的第 199 行

So if the splitted data arrives so quickly that the asynchronous task receives multiple chunks of data within a single node's event loop, node-fetch receives multiple jason data.因此,如果拆分后的数据到达速度如此之快,以至于异步任务在单个节点的事件循环中接收到多个数据块, node-fetch接收到多个 jason 数据。

That's when the error occurs.那是错误发生的时候。 Run the following code with console.log added.在添加了console.log的情况下运行以下代码。 Then you can confirm that when error occurs, the multiple jason objects are kept in a chunk .然后你可以确认当错误发生时,多个 jason 对象被保存在一个chunk中。

const fetch = require('node-fetch');

async function main () {
  const response = await fetch('https://httpbin.org/stream/3');
  try {
    for await (const chunk of response.body) {
      console.log("------chunk-----\n", chunk.toString());
      console.log("Char at 310 -- 315", chunk.toString().substring(310, 315));
      console.log(JSON.parse(chunk.toString()));
    }
  } catch (err) {
    console.error(err.stack);
  }
}

main()

For this site, you can split the data by yourself when the error occurs as follows.对于本站,报错时可以自行拆分数据如下。

const fetch = require('node-fetch');

async function main () {
  const response = await fetch('https://httpbin.org/stream/3');
  try {
    for await (const chunk of response.body) {
      try {
        console.log(JSON.parse(chunk.toString()));
      } catch (_) {
        console.log("------ Handling multiple chunks ------");
        chunk.toString().split("\n").slice(0, -1).forEach(d => console.log(JSON.parse(d)));
      }
    }
  } catch (err) {
    console.error(err.stack);
  }
}
main()

When you use Fetch API with a browser, you can actually write your own ReadableStreamReader and implement the strategy how to handle the splitted data.当您在浏览器中使用 Fetch API 时,您实际上可以编写自己的ReadableStreamReader并实现如何处理拆分数据的策略。

Update:更新:

You can simply use stream-json library's jsonl Parser as follows:您可以简单地使用stream-json库的jsonl Parser ,如下所示:

const { parser: jsonlParser } = require('stream-json/jsonl/Parser');

async function main () {
  const response = await fetch('https://httpbin.org/stream/5');
  response.body.pipe(jsonlParser())
    .on('data', ({ key, value }) => console.log(value))
    .on('end', () => console.log("Parsing done."))
    .on('error', err => console.log(err.message));
}

main();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM