【问题标题】:How do I stream JSON from node?如何从节点流式传输 JSON?
【发布时间】:2016-01-21 21:45:52
【问题描述】:

我正在开发一个基于 node/express(技术上为Sails)的服务,该服务将用于检索大量项目。多次调用将需要以 JSON 序列化数组的形式返回数千个项目。

内部节点将是一个基本的控制循环来检索页面中的项目。将检索每个页面,执行一些次要处理,然后将其项目返回给客户端。

目前我正在做一个“存储和转发”的方法,其中每个页面的项目是 concat() 到一个 results 数组,然后一旦检索到所有项目,就会返回结果。

我想做更多的是一种产量或流式方法,其中项目一旦准备好就被添加到响应中——避免需要构建一个大型内存集合并开始发送尽快提供可用数据。

【问题讨论】:

  • 这应该可以通过 WebSockets 实现。我认为 WebSockets 是作为可写流实现的,因此您可以为出现的每个块 socket.write(json)。我不确定,也没有时间检查,所以我没有添加它作为答案。

标签: json node.js express streaming sails.js


【解决方案1】:

您可以使用类似这样的方式直接写入 res 对象

var data=[/* a large array of json objects*/];//
//let us divide this large array into chunks of smaller array
function chunk(arr, chunkSize) {
    var R = [];
    for (var i = 0; i < arr.length; i += chunkSize)
        R.push(arr.slice(i, i + chunkSize));
    return R;
}
var new_data=chunk(data,10);//[/* array of arrays*/], chunk size is 10
res.writeHead(200, {
        'Content-Type': 'application/json',
        'Transfer-Encoding': 'chunked'
})
res.write("["); //array starting bracket
for (var i = 0; i < new_data.length - 1; i++) {

        res.write(JSON.stringify(new_data[i]) + ',');

}
res.write(JSON.stringify(new_data[new_data.length-i]));
res.write("]"); //array ending bracket
res.end();

在客户端使用类似的东西

// using axios
var url = 'http://localhost:3000';
axios.get(url, { responseType: 'stream' }).then(handleRes);

function handleRes(res) {
    // res.headers available here
    res.data.on('data', data => {
        data = data.toString(); // utf8 by default, change if needed

        if (data === '[' || data === ']') return console.log(data);

        var jsonStr = data.slice(-1) === '}' ? data : data.slice(0, -1);
        console.log(JSON.parse(jsonStr));
    })
}

【讨论】:

    【解决方案2】:

    如果您需要从所有数据中生成一个大的 JSON 字符串,您几乎只能将所有内容存储在内存中,然后 JSON.stringify-ing 它。

    另一种方法是让每个项目都是一个单独的 JSON 字符串,使用换行符作为分隔符。这样,一旦您处理了一个项目,您就可以将其字符串化并使用 Node 流将其传输到您的响应中,并且在客户端中,您也可以逐行处理接收到的数据。它会是这样的:

    // For each page of data you get, loop over the items like you say
    for item in dataset // Yes that's Coffeescript
    
      // Manipulate the item as you need, then make a JSON string out of it
      jsonStr = JSON.stringify(item) + '\n'
    
      // Pipe the string to your http response
      jsonStr.toStream().pipe(res) // Assuming 'res' is the Express response object
    

    这不是解决您的问题的唯一方法,但特别是如果您喜欢使用 JSON,它是最简单的实现之一。虽然我对 Sails 没有任何经验,但我想基本的实现是一样的。

    希望我的回答对你有帮助,如果不欢迎评论。

    注意:.toStream() 方法来自我的模块 streammagic,但当然还有其他方法可以从字符串中生成流。

    【讨论】:

      猜你喜欢
      • 2019-01-03
      • 2017-05-17
      • 2014-08-26
      • 2012-09-09
      • 2017-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-19
      相关资源
      最近更新 更多