使用 node-fetch 无法解析 json 流
Fail to parse on a json stream using node-fetch
我 运行 来自 node-fetch
流功能的示例代码。
有时它可以成功解析块,有时 return error msg 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()
有人知道为什么吗?我可以依靠大块吗?
通过请求https://httpbin.org/stream/3
,服务器通过流发送分成3个块的数据。客户端(在本例中是您的节点脚本)与服务器保持连接并继续接收数据并将它们分成块。
每次完成单个异步任务时,node-fetch
只是将数据分成块,如您在此处所见:line 199 of body.js.
因此,如果拆分后的数据到达速度如此之快,以至于异步任务在单个节点的事件循环中接收到多个数据块,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();
我 运行 来自 node-fetch
流功能的示例代码。
有时它可以成功解析块,有时 return error msg 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()
有人知道为什么吗?我可以依靠大块吗?
通过请求https://httpbin.org/stream/3
,服务器通过流发送分成3个块的数据。客户端(在本例中是您的节点脚本)与服务器保持连接并继续接收数据并将它们分成块。
每次完成单个异步任务时,node-fetch
只是将数据分成块,如您在此处所见:line 199 of body.js.
因此,如果拆分后的数据到达速度如此之快,以至于异步任务在单个节点的事件循环中接收到多个数据块,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();