【问题标题】:NodeJS request multiple api endpointsNodeJS 请求多个 api 端点
【发布时间】:2016-01-04 14:24:43
【问题描述】:

好的,我正在尝试使用请求模块向 API 端点发出两个或更多请求。我正在渲染一个 HTML 文件并使用以下代码将返回的 JSON 传递给车把模板:

res.render('list.html', {
  title: 'List',
  data: returnedJSON
}

然后我可以很容易地在我的车把模板中迭代这个 JSON。

我遇到的问题是,我现在需要使用多个数据源,其中将根据类别 JSON 响应构建类别列表,并根据员工 JSON 响应构建员工列表。我想要一个可以做到这一点的简单解决方案,但可以扩展它以使用任意数量的数据源。

以下是我拥有的一个数据源的完整代码 sn-p:

request({
    url: 'https://api.com/categories',
    headers: {
        'Bearer': 'sampleapitoken'
    }
}, function(error, response, body) {
    if(error || response.statusCode !== 200) {
        // handle error
    } else {
        var json = JSON.parse(body);
        res.render('list.html', {
            title: 'Listing',
            data: json
        });
    }
});

这对一个端点很有效,但如前所述,我现在需要使用多个请求并拥有多个数据源,例如:

request({
    url: ['https://api.com/categories','https://api.com/staff'],
    headers: {
        'Bearer': 'sampleapitoken'
    }
}, function(error, response, body1, body2) {
    if(error || response.statusCode !== 200) {
        // handle error
    } else {
        var json1 = JSON.parse(body1);
        var json2 = JSON.parse(body2);
        res.render('list.html', {
            title: 'Listing',
            staff: json1,
            categories: json2
        });
    }
});

我很欣赏上述内容并非如此,但我希望这可以帮助传达我想要实现的目标。

提前致谢:)

【问题讨论】:

  • 你不能为每个 URL 创建新的请求对象并在最后将它们汇集起来吗?
  • 这是一个好点 ;)

标签: javascript json node.js express requestjs


【解决方案1】:

您可以使用async 库来映射您的请求对象并将它们传递给实际请求并在一个回调中返回所有结果。

var async = require("async");
var request = require("request");

// create request objects
var requests = [{
  url: 'https://api.com/categories',
  headers: {
    'Bearer': 'sampleapitoken'
  }
}, {
  url: 'https://api.com/staff',
  headers: {
    'Bearer': 'sampleapitoken'
  }
}];

async.map(requests, function(obj, callback) {
  // iterator function
  request(obj, function(error, response, body) {
    if (!error && response.statusCode == 200) {
      // transform data here or pass it on
      var body = JSON.parse(body);
      callback(null, body);
    } else {
      callback(error || response.statusCode);
    }
  });
}, function(err, results) {
  // all requests have been made
  if (err) {
    // handle your error
  } else {
    console.log(results);
    for (var i = 0; i < results.length; i++) {
      // request body is results[i]
    }
  }
});

然而,更简单的方法是利用 Promise,这可以通过 bluebird 和 Promisifying 请求库来完成,或者使用已经承诺的请求库 request-promise。您仍然需要包含一个 Promise/A+ 库来异步映射结果。

var Promise = require("bluebird");
var request = require('request-promise');

// create request objects
var requests = [{
  url: 'https://api.com/categories',
  headers: {
    'Bearer': 'sampleapitoken'
  }
}, {
  url: 'https://api.com/staff',
  headers: {
    'Bearer': 'sampleapitoken'
  }
}];

Promise.map(requests, function(obj) {
  return request(obj).then(function(body) {
    return JSON.parse(body);
  });
}).then(function(results) {
  console.log(results);
  for (var i = 0; i < results.length; i++) {
    // access the result's body via results[i]
  }
}, function(err) {
  // handle all your errors here
});

请务必注意,所有最新版本的节点和浏览器都支持开箱即用的 Promises,并且无需外部库即可实现。

【讨论】:

  • 这太棒了,正是我想要的。但是我得到以下TypeError: request(...).spread is not a function
  • 啊,这是一个神器。我将从示例中删除它。应该是then,而不是spread
  • 很棒的答案,帮助我克服了程序中的一个大障碍 :),道具!
  • @Seth 你知道为什么你不能通过 request-promise 访问 Promise 吗?我认为 request-promise 暴露了 bluebird Promise 对象,但 rp.promise().map() 似乎对我不起作用。 github.com/request/…
  • 嗯。 @SebastianThomas Promise.map 是一个类函数,因此像在示例中一样调用它。我从来没有直接利用 Bluebird 的 Promise 实例,总是需要我自己的,或者最近使用的节点的内置类
【解决方案2】:

似乎承诺会有所帮助。

最简单的可能是创建一个新的请求方法来返回一个承诺(或使用 Bluebird 等进行承诺),然后等待所有承诺完成,然后处理数据

function doReq(url, what) {
    return new Promise(function(resolve, reject) {
        request({
            url: url,
            headers: {
                'Bearer': 'sampleapitoken'
            }
        }, function(error, response) {
            if(error || response.statusCode !== 200) {
                reject(error);
            } else {
                var data = {};
                (Array.isArray(what) ? what : [what]).forEach(function(item, index) {
                    data[item] = JSON.parse(arguments[index + 2]);
                });
                resolve( data );
            }
        });
    });
}

Promise.all([
    doReq('https://api.com/categories', 'data'), 
    doReq(['https://api.com/categories','https://api.com/staff'], ['staff', 'categories'])
]).then(function() {
    var obj = {title : 'Listing'};
    [].slice.call(arguments).forEach(function(arg) {
        Object.keys(arg).forEach(function(key) {
            obj[key] = arg[key];
        });
    });
    res.render('list.html', obj);
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    • 2016-04-26
    • 2018-04-08
    • 1970-01-01
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多