使用 fetch 获取 JSON 对象流 aANDJSON 的属性

Get properties of a JSON object streamed as NDJSON using fetch

我正在尝试使用 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) 也不起作用。我怎样才能解决这个问题?

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

  1. 我怀疑 API 不管你说什么,一直在发送不止一行数据,
  2. ndjson 不是标准的 JSON 字符串并且失败,
  3. 如果您不添加适当的处理,节点中的承诺往往会无提示地失败。

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

我提供的解决方案是将 fetch 与 scramjet 一起使用,如下所示:

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

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

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

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

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

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

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

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

你不必使用超燃冲压发动机,你可以像这样使用现有的模块来解决它:

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)) 或你可能需要的任何东西,但最终可以通过任何一种方式实现目标.