在Node.js中,将多个HTTP请求合并为一个HTTP请求的方法。

9

我正在尝试在单个URL调用中调用多个URL,并将其JSON响应推送到数组中,并将该数组作为响应发送给最终用户。

我的代码如下:

var express = require('express');

var main_router = express.Router();

var http = require('http');

urls = [
"http://localhost:3010/alm/build_tool",
"http://localhost:3010/alm/development_tool",
"http://localhost:3010/alm/project_architecture"];

var responses = [];

main_router.route('/')

.get(function (req, res) {

var completed_requests = 0;

for (url in urls) {

  http.get(url, function(res) {

    responses.push(res.body);

    completed_request++;

    if (completed_request == urls.length) {

        // All download done, process responses array
    }
  });
}
res.send(responses);
});

我也尝试使用npm请求模块来实现这个功能。

当我运行此代码时,它只返回NULL或一些仅包含标头的随机输出。

我的目标是在单个节点get请求中调用多个URL,并将其JSON输出附加到数组中并发送给最终用户。

谢谢


你必须使用回调函数,或者我可以建议使用Async模块 https://github.com/caolan/async。 - michelem
请参考这个答案。您应该使用res.on('end', function...等待响应结束。 - toasted_flakes
2个回答

23

试试这段代码:

const async = require('async');
const request = require('request');

function httpGet(url, callback) {
  const options = {
    url :  url,
    json : true
  };
  request(options,
    function(err, res, body) {
      callback(err, body);
    }
  );
}

const urls= [
  "http://localhost:3010/alm/build_tool",
  "http://localhost:3010/alm/development_tool",
  "http://localhost:3010/alm/project_architecture"
];

async.map(urls, httpGet, function (err, res){
  if (err) return console.log(err);
  console.log(res);
});

说明: 此代码使用了 asyncrequest node 包。按照定义,async.map 需要 3 个参数:第一个是数组,第二个是想要对该数组中每个元素调用的迭代器函数,第三个是在 async.map 完成处理后调用的回调函数。

map(arr, iterator, [callback])

通过将 arr 中的每个值映射到迭代器函数中,生成新的值数组。迭代器将使用 arr 中的项以及处理完成时的回调进行调用。每个回调都有两个参数:一个错误和来自 arr 的已转换的项。如果迭代器通过其回调传递了错误,则立即使用该错误调用主回调(针对 map 函数)。

注意:所有对迭代器函数的调用都是并行的。

在你的 httpGet 函数内部,你正在使用传递的 url 调用 request 函数,并明确告知响应格式为 json。当 request 处理完成后,将使用三个参数 err(如果有),res - 服务器响应,body - 响应主体来调用回调函数。如果没有来自 request 的错误,则 async.map 将这些回调的结果收集为一个数组,并在最后将该数组传递给其第三个回调函数。否则,如果 (err) 为 true,则 async.map 函数停止执行并使用 err 调用其回调。


这里的request是什么?async又是什么?在回答中使用库是可以的,但只有在您指定使用了哪些库时才可以:P - birdoftheday
好的,提问者似乎已经知道这些包了。无论如何,为其他用户更新一下。 - yoogeeks
谢谢。是否有可能将所有数据主体合并为一个?如果我从多个URL下载JSON,它看起来是这样的http://i.imgur.com/nX1IRla.png。您知道如何将它们合并到一个数据主体下吗? - Suhaib
你可以简单地循环遍历每个响应体并将其添加到最终结果中。但是,如果你使用分页功能时要小心。 - yoogeeks

4

我建议使用 async 库。

async.map(urls, http.get, function(err, responses){
  if (err){
    // handle error
  }
  else {
    res.send responses
  }
})

上述代码片段将并行执行每个url的 http.get 调用,在所有响应接收后,将使用所有调用的结果调用您的回调函数。
如果您想按顺序调用url,可以使用async.mapSeries。如果您想限制并发请求的数量,则可以使用async.mapLimit

感谢您的评论。如果您有任何可用的代码,请分享。我已经尝试了以下代码,但没有得到任何响应。main_router.route('/') .get(function (req, res) {var test = async.each(urls, http.get, function(err, responses, callback){ if (err){ // 处理错误 } else {return responses; }}) res.send(test); res.end(); }); - Vaibhav Jain
注意:async.each回调函数不处理响应。如果您需要在调用结束时获取响应,则应使用async.map,它将在回调函数中以数组形式返回每个HTTP请求的响应。 - yoogeeks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接