2013-05-31 90 views
33

我正在使用快速模块在Node.JS中创建一个Restful API。在我的服务中,我向外部端点(服务器端)发出额外的http请求,并且需要将这些http请求中的数据返回给我的Web服务请求主体。Node.JS等待发出HTTP请求的REST服务的回调

我已经确认,如果我使用console.log对Web服务进行的所有操作,我正在获取我需要的数据。但是,当我尝试将这些值返回给服务时,它们会返回空值。我知道这是因为异步,回调并没有等待http请求完成。

有没有办法让这项工作?

+0

您需要接受回调。 – SLaks

回答

41

通常的做法是使用async模块。

npm install async 

async模块具有原语来处理各种形式的异步事件。

在您的情况下,async#parallel调用将允许您同时向所有外部API发出请求,然后将结果合并以返回给请求者。

由于您正在进行外部http请求,因此您可能会发现request模块也很有用。

npm install request 

使用requestasync#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

+0

这看起来很有希望。我将如何援引这一点? – Rob

+0

想通了。谢谢! – Rob

+0

哇。你只需要节省几小时的搜索时间 –

17

Node.js是关于回调的。除非API调用是同步的(很少发生并且不应该这样做),否则永远不会从这些调用返回值,而是使用回调方法中的结果进行回调,或者调用快速方法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); 
    } 
    }) 
} 

例从丹尼尔的回答是:使用wait.for

3

wait.for https://github.com/luciotato/waitfor

其他答案的例子(异步),但使用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); 
      }); 
}