繁体   English   中英

当 JSON 过长时,JSON.parse() 会抛出错误

[英]JSON.parse() throws error when JSON gets too long

我在 node.js 中生成了一个 python child_process,它返回 JSON 数据。 在我的 python 文件中,我使用了 json.dumps() ,然后将其传递回节点。 每当 JSON 中的列表“结果”包含超过 62 个条目时,我的 node.js 服务器在尝试解析它时就会死机。 否则一切正常吗?

即使节点应用程序死亡,数据仍然会正确发送回客户端。

仅在调用 JSON.parse() 时才会抛出错误消息,但我不能在此处省略,因为从 python 接收到的数据是缓冲格式:

<Buffer 7b 0d 0a 20 20 22 70 61 72 61 6d 65 74 65 72 73 22 3a 20 5b 0d 0a 20 20 20 20 7b 0d 0a 20 20 20 20 20 20 22 70 72 6f 70 65 72 74 79 22 3a 20 22 42 65 ... 9136 more bytes>
<Buffer 0d 0a>

有谁知道问题可能是什么?

抛出的错误消息是:

undefined:2

SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at Socket.<anonymous> (D:\Projects\data-farming-framework-api\app.js:52:23)

    at Socket.emit (events.js:310:20)
    at addChunk (_stream_readable.js:286:12)
    at readableAddChunk (_stream_readable.js:268:9)
    at Socket.Readable.push (_stream_readable.js:209:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:186:23)

我的 node.js 代码:

app.post('/api/ps/executeExperiments', async (req, res, next) => {
  let path = req.body.path;
  let experiments = JSON.stringify(req.body.data);
  let python = await spawn('python', ['./plantsim.py', 'execute_experiments()', path, experiments]);
  python.stdout.on('data', data => {
    if (data.toString() == 'ERROR') {
      callback(new Error('ERROR'))
    }
    let result = JSON.parse(data);
    res.send(result);
  });
});

返回的 JSON格式如下:

{
  parameters: [
    { property: 'Bearbeitungszeit', object: 'Einzelstation' },
    { property: 'Bearbeitungszeit', object: 'Einzelstation2' }
  ],
  results: [
    { id: 1, input: 252, output: 249, values: [Array] },
    { id: 2, input: 198, output: 195, values: [Array] },
    { id: 3, input: 165, output: 162, values: [Array] },
    { id: 4, input: 204, output: 201, values: [Array] },
    { id: 5, input: 169, output: 166, values: [Array] },
    { id: 6, input: 239, output: 236, values: [Array] },
    { id: 7, input: 225, output: 222, values: [Array] },
    { id: 8, input: 312, output: 309, values: [Array] },
    { id: 9, input: 324, output: 321, values: [Array] },
    { id: 10, input: 248, output: 245, values: [Array] },
    { id: 11, input: 199, output: 196, values: [Array] },
    { id: 12, input: 186, output: 183, values: [Array] },
    { id: 13, input: 161, output: 158, values: [Array] },
    { id: 14, input: 149, output: 146, values: [Array] },
    { id: 15, input: 175, output: 172, values: [Array] },
    { id: 16, input: 201, output: 198, values: [Array] },
    { id: 17, input: 242, output: 239, values: [Array] },
    { id: 18, input: 162, output: 159, values: [Array] },
    { id: 19, input: 184, output: 181, values: [Array] },
    { id: 20, input: 157, output: 154, values: [Array] },
    { id: 21, input: 160, output: 157, values: [Array] },
    { id: 22, input: 290, output: 287, values: [Array] },
    { id: 23, input: 358, output: 355, values: [Array] },
    { id: 24, input: 153, output: 150, values: [Array] },
    { id: 25, input: 155, output: 152, values: [Array] },
    { id: 26, input: 195, output: 192, values: [Array] },
    { id: 27, input: 174, output: 171, values: [Array] },
    { id: 28, input: 269, output: 266, values: [Array] },
    { id: 29, input: 341, output: 338, values: [Array] },
    { id: 30, input: 263, output: 260, values: [Array] },
    { id: 31, input: 156, output: 153, values: [Array] },
    { id: 32, input: 167, output: 164, values: [Array] },
    { id: 33, input: 295, output: 292, values: [Array] },
    { id: 34, input: 230, output: 227, values: [Array] },
    { id: 35, input: 189, output: 186, values: [Array] },
    { id: 36, input: 172, output: 169, values: [Array] },
    { id: 37, input: 254, output: 251, values: [Array] },
    { id: 38, input: 182, output: 179, values: [Array] },
    { id: 39, input: 206, output: 203, values: [Array] },
    { id: 40, input: 232, output: 229, values: [Array] },
    { id: 41, input: 259, output: 256, values: [Array] },
    { id: 42, input: 159, output: 156, values: [Array] },
    { id: 43, input: 305, output: 302, values: [Array] },
    { id: 44, input: 151, output: 148, values: [Array] },
    { id: 45, input: 181, output: 178, values: [Array] },
    { id: 46, input: 302, output: 299, values: [Array] },
    { id: 47, input: 187, output: 184, values: [Array] },
    { id: 48, input: 245, output: 242, values: [Array] },
    { id: 49, input: 149, output: 146, values: [Array] },
    { id: 50, input: 279, output: 276, values: [Array] },
    { id: 51, input: 215, output: 212, values: [Array] },
    { id: 52, input: 170, output: 167, values: [Array] },
    { id: 53, input: 288, output: 285, values: [Array] },
    { id: 54, input: 329, output: 326, values: [Array] },
    { id: 55, input: 283, output: 280, values: [Array] },
    { id: 56, input: 193, output: 190, values: [Array] },
    { id: 57, input: 177, output: 174, values: [Array] },
    { id: 58, input: 348, output: 345, values: [Array] },
    { id: 59, input: 265, output: 262, values: [Array] },
    { id: 60, input: 219, output: 216, values: [Array] },
    { id: 61, input: 352, output: 349, values: [Array] },
    { id: 62, input: 151, output: 148, values: [Array] }
  ]
}

值也是一个列表,但我不知道为什么它没有正确显示在终端中。 数据仍然存在,因为它被正确地传递给客户端。

data事件在任意边界上传递数据块。 只要您将整个 JSON 放在一个块中(您无法控制),您的代码可能恰好可以工作。 但是,一旦数据变得足够大,需要足够长的时间来生成它以超过一个块的形式发送,那么您的代码就会在试图解析单个数据块时死掉。 这就是为什么它取决于大小。 在一定大小的数据中,它将开始以超过一个块的形式到达。 而且,您不能将每个块分别解析为 JSON (因此您的JSON.parse()错误。

相反,如果要将其解析为 JSON,则需要累积所有块,然后在完成后解析整个内容。 JSON 不是一种可以轻松增量解析的格式(有 JSON stream 代码可以做到,但工作量很大)。

app.post('/api/ps/executeExperiments', async (req, res, next) => {
  let path = req.body.path;
  let experiments = JSON.stringify(req.body.data);
  let python = spawn('python', ['./plantsim.py', 'execute_experiments()', path, experiments]);

  let allData = [];
  // collect from all the data events here
  python.stdout.on('data', data => {
    allData.push(data.toString());
  }).on('error', e => {
     console.log(e);
     res.sendStatus(500);
  }).on('close', () => {
     // we have all data now
     let result = allData.join(allData, "");
     if (result.startsWith('ERROR')) {
        console.log(result);
        res.sendStatus(500);
     } else {
        res.send(allData);
     }
  });
});

在您现有的代码中,什么是callback() 你没有表现出来,这让我很困惑,所以我把它删除了。

如果收到错误,您还需要向传入的 POST 请求发送错误响应。

而且,在spawn()的返回值上使用await是没有意义的。 它不会返回 promise 所以await没有做任何有用的事情。

此外,似乎甚至不需要解析 JSON。 如果您只想解析它然后使用res.send()将其发送出去,那么res.send()要做的就是再次将其转回 JSON 。 所以,也许你真正需要做的只是 stream python.stdout 作为你的回应?

问题不在于长文件,问题在于您尝试收集数据的方式。 python.stdout.on是数据的 stream。 数据来自块。 所以你需要收集所有数据然后返回响应。 您可以使用下面给出的基本 util 方法进行简化。

const spawn = require("child_process").spawn;

function run(path, experiments) {
  let command = spawn("python", [
    "./plantsim.py",
    "execute_experiments()",
    path,
    experiments,
  ]);
  return new Promise((resolve) => {
    var result = "";
    command.stdout.on("data", function (data) {
      result += data.toString();
    });
    command.on("close", function (code) {
      resolve(result);
    });
  });
}
app.post("/api/ps/executeExperiments", async (req, res, next) => {
  let path = req.body.path;
  let experiments = JSON.stringify(req.body.data);
  const data = await run(path, experiments);
  res.send(result);
});

如果您只是返回文件[不解析或转换],您只需 pipe 将数据发送到响应。

样本:

const { spawn } = require("child_process");
const express = require("express");
const app = express();

app.get("/json", (req, res) => {
  let command = spawn("cat", [
    __dirname + "/test.json",
  ]);
  command.stdout.pipe(res)
  command.on("close", function (data) {
    console.log("done writing");
  });
});
app.listen(3000)

暂无
暂无

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

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