我正在使用express模块在Node.JS中创建Restful API。在我的服务中,我正在向外部端点(服务器端)发出额外的http请求,我需要将这些http请求中的数据返回给我的Web服务请求主体。
我已经确认,如果我在Web服务正在执行的所有操作上使用console.log
,我将获得所需的数据。但是,当我尝试将这些值返回给服务时,它们会返回Null。我知道这是因为异步并且回调不等待http请求完成。
有没有办法让这项工作?
答案 0 :(得分:41)
通常的做法是使用async模块。
npm install async
async
模块具有处理各种形式的异步事件的原语。
在您的情况下,async#parallel
调用将允许您同时向所有外部API发出请求,然后将结果合并以返回给您的请求者。
由于您正在制作外部http请求,因此您可能会发现request模块也很有用。
npm install request
使用request
和async#parallel
路由处理程序看起来像这样......
var request = require('request');
var async = require('async');
exports.handler = function(req, res) {
async.parallel([
/*
* First external endpoint
*/
function(callback) {
var url = "http://external1.com/api/some_endpoint";
request(url, function(err, response, body) {
// JSON body
if(err) { console.log(err); callback(true); return; }
obj = JSON.parse(body);
callback(false, obj);
});
},
/*
* Second external endpoint
*/
function(callback) {
var url = "http://external2.com/api/some_endpoint";
request(url, function(err, response, body) {
// JSON body
if(err) { console.log(err); callback(true); return; }
obj = JSON.parse(body);
callback(false, obj);
});
},
],
/*
* Collate results
*/
function(err, results) {
if(err) { console.log(err); res.send(500,"Server Error"); return; }
res.send({api1:results[0], api2:results[1]});
}
);
};
您还可以阅读其他回调排序方法here。
答案 1 :(得分:18)
Node.js就是回调。除非API调用是同步的(很少见且不应该完成),否则永远不会从这些调用中返回值,而是使用回调方法中的结果进行回调,或者调用express方法res.send
用于调用Web请求的优秀库是request.js
让我们来看看调用谷歌这个非常简单的例子吧。使用res.send,您的express.js代码可能如下所示:
var request = require('request');
app.get('/callGoogle', function(req, res){
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
// from within the callback, write data to response, essentially returning it.
res.send(body);
}
})
});
或者,您可以将回调传递给调用Web请求的方法,并从该方法中调用该回调:
app.get('/callGoogle', function(req, res){
invokeAndProcessGoogleResponse(function(err, result){
if(err){
res.send(500, { error: 'something blew up' });
} else {
res.send(result);
}
});
});
var invokeAndProcessGoogleResponse = function(callback){
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
status = "succeeded";
callback(null, {status : status});
} else {
callback(error);
}
})
}
答案 2 :(得分:3)
Wait.for https://github.com/luciotato/waitfor
使用wait.for的其他答案的例子:
来自Daniel's Answer(async)的示例,但使用Wait.for
var request = require('request');
var wait = require('wait.for');
exports.handler = function(req, res) {
try {
//execute parallel, 2 endpoints, wait for results
var result = wait.parallel.map(["http://external1.com/api/some_endpoint"
,"http://external2.com/api/some_endpoint"]
, request.standardGetJSON);
//return result
res.send(result);
}
catch(err){
console.log(err);
res.end(500,"Server Error")
}
};
//wait.for requires standard callbacks(err,data)
//standardized request.get:
request.standardGetJSON = function ( options, callback) {
request.get(options,
function (error, response, body) {
//standardized callback
var data;
if (!error) data={ response: response, obj:JSON.parse(body)};
callback(error,data);
});
}