0

我正在尝试使用 fetch 从 API 获取 NDJSON 数据。由于我只需要一个 JSON 对象,因此我想使用 fetch 来完成此操作。API提供的数据格式为(我自己格式化,实际响应为单行):

{
  "a": "value",
  "b": "value",
  "c": "value",
  "d": "value",
  "e": "value"
}

当我简单地记录数据时,一切正常,并且我将上述响应作为一个对象:

const obj = await fetch(url, {
  method: "GET"
}).then(res => res.json());
console.log(obj);

但是,当我尝试记录该对象的属性之一时,没有记录任何内容(没有错误):

const obj = await fetch(url, {
  method: "GET"
}).then(res => res.json());
console.log(obj.a);

即使记录JSON.stringify(obj)也不起作用。我该如何解决这个问题?

4

1 回答 1

2

我想深入了解发生的事情并指出您遇到的几个问题 - 这可能使整个事情比应有的更难解决。

  1. 我怀疑无论您说什么,API 都会不断发送多行数据,
  2. ndjson 不是标准的 JSON 字符串并且失败,
  3. 如果您不添加适当的处理,节点中的 Promise 往往会以静默方式失败。

这三个问题导致结果<nothing>应该是一个错误,说明文件无法解析。

我提供的解决方案是像这样使用 fetch scramjet

const {StringSteram} = require("scramjet");

const stream = StringStream
  .from(async () => (await fetch(url)).body)
  .JSONParse()
;

StringStream.from 接受一个流或返回一个的方法,然后魔术发生在 JSONParse

  • 该方法将每一行分开
  • 然后将该行解析为 json

所以现在stream是一个流动的对象列表。在 node >= 12 中,您可以简单地循环遍历它:

for await (const item of stream) {
   console.log(item);
}

并且由于生成的流类具有一些生物舒适功能,如果您只想将数据作为Array

console.log(await stream.toArray());

您不必使用 scramjet,只需使用现有模块即可,如下所示:

const { createInterface } = require("readline");
const { PassThrough } = require("stream");

const input = (await fetch(url)).body;
const output = new PassThrough();
createInterface({ input, output });

for await (const line of output) {
   console.log(JSON.parse(line));
}

两种解决方案都会带您到那里 -scramjet您可以向流中添加更多处理,例如:stream.filter(item => checkValid(item))或您可能需要的任何内容,但最终可以通过任何一种方式达到目标。

于 2021-05-28T15:16:19.637 回答