簡體   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