0

node-fetch我从流功能运行示例代码。有时它可以成功解析块,有时返回错误消息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()

有谁知道为什么?我可以依赖大块吗?

4

1 回答 1

1

通过请求https://httpbin.org/stream/3,服务器通过流将数据分成 3 个块发送。客户端(在这种情况下是您的节点脚本)与服务器保持连接并继续接收数据并将它们分成块。

node-fetch每次完成单个异步任务时,都会将数据简单地拆分为块,如您在此处看到的:body.js的第 199 行

因此,如果拆分的数据到达如此之快以至于异步任务在单个节点的事件循环中node-fetch接收到多个数据块,则接收到多个 jason 数据。

这就是错误发生的时候。运行以下代码并console.log添加。然后您可以确认当发生错误时,多个 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()

对于本站,出现如下错误时可以自行拆分数据。

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()

当您在浏览器中使用 Fetch API 时,您实际上可以编写自己的ReadableStreamReader并实现如何处理拆分数据的策略。

更新:

您可以简单地使用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();
于 2021-08-09T04:23:23.077 回答