简体   繁体   English

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

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

I have spawned a python child_process in node.js that returns JSON data.我在 node.js 中生成了一个 python child_process,它返回 JSON 数据。 In my python file I used json.dumps() before passing it back to node.在我的 python 文件中,我使用了 json.dumps() ,然后将其传递回节点。 Whenever the list "results" in the JSON contains more than 62 entries, my node.js server dies when trying to parse it.每当 JSON 中的列表“结果”包含超过 62 个条目时,我的 node.js 服务器在尝试解析它时就会死机。 Otherwise it works all fine?否则一切正常吗?

Even when the node app dies, the data gets still sent back correctly to the client.即使节点应用程序死亡,数据仍然会正确发送回客户端。

The error message is only thrown when calling JSON.parse(), but I cannot leave it out here, because the received data from python is in a buffered format:仅在调用 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>

Has anyone an idea what the problem could be?有谁知道问题可能是什么?

The thrown error message is:抛出的错误消息是:

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)

My node.js code:我的 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);
  });
});

The returned JSON has following format:返回的 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] }
  ]
}

Values is also a list, however i don't know why it is not displayed in the terminal correctly.值也是一个列表,但我不知道为什么它没有正确显示在终端中。 The data is still there as it gets passed to the client correctly.数据仍然存在,因为它被正确地传递给客户端。

data events deliver chunks of data on arbitrary boundaries. data事件在任意边界上传递数据块。 As long as you are getting the entire JSON in one chunk (something you do not control), your code probably just happens to work.只要您将整个 JSON 放在一个块中(您无法控制),您的代码可能恰好可以工作。 But, as soon as the data gets large enough of takes long enough to generate that it gets sent in more than one chunk, then your code dies trying to parse an individual chunk of data.但是,一旦数据变得足够大,需要足够长的时间来生成它以超过一个块的形式发送,那么您的代码就会在试图解析单个数据块时死掉。 This is why it is size dependent.这就是为什么它取决于大小。 At some size of data, it will start arriving in more than one chunk.在一定大小的数据中,它将开始以超过一个块的形式到达。 And, you can't parse each chunk as JSON separately (thus your JSON.parse() error.而且,您不能将每个块分别解析为 JSON (因此您的JSON.parse()错误。

Instead, if you're going to parse it into JSON, you need to accumulate all the chunks and then when it's done, parse the entire thing.相反,如果要将其解析为 JSON,则需要累积所有块,然后在完成后解析整个内容。 JSON is not a format that can easily be incrementally parsed (there is JSON stream code that can do it, but it's a lot of work). 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);
     }
  });
});

In your existing code what is callback() ?在您现有的代码中,什么是callback() You don't show that and it has me confused so I removed it.你没有表现出来,这让我很困惑,所以我把它删除了。

You also need to send an error response to the incoming POST request if you get an error.如果收到错误,您还需要向传入的 POST 请求发送错误响应。

And, there's no point to using await on the return value from spawn() .而且,在spawn()的返回值上使用await是没有意义的。 It doesn't return a promise so await doesn't do anything useful.它不会返回 promise 所以await没有做任何有用的事情。

Also, it appears there is no need to even parse the JSON.此外,似乎甚至不需要解析 JSON。 If you're going to just parse it and then send it right off with res.send() , all res.send() is going to do is turn it back into JSON again.如果您只想解析它然后使用res.send()将其发送出去,那么res.send()要做的就是再次将其转回 JSON 。 So, perhaps all you really need to do it to just stream python.stdout as your response?所以,也许你真正需要做的只是 stream python.stdout 作为你的回应?

The issue is not with the long file, the issue is with the way you tried to collect data.问题不在于长文件,问题在于您尝试收集数据的方式。 python.stdout.on is the stream of data. python.stdout.on是数据的 stream。 Data comes in the chunk.数据来自块。 So you need to collect all data then return to response.所以你需要收集所有数据然后返回响应。 You can simplify, using basic util method as given below.您可以使用下面给出的基本 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);
});

If you are just returning file[no parse or transform] you can just pipe the data to the response.如果您只是返回文件[不解析或转换],您只需 pipe 将数据发送到响应。

Sample:样本:

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