2013-05-31 110 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); 
      }); 
}