Node.JS Ждите обратного вызова службы REST, которая делает запрос HTTP
Я использую экспресс-модуль для создания Restful API в Node.JS. В моем сервисе я делаю дополнительные HTTP-запросы для внешних конечных точек (на стороне сервера), и мне нужно вернуть данные из этих http-запросов в тело запроса веб-службы.
Я подтвердил, что если я использую console.log
для всех действий, которые проводит веб-служба, я получаю нужные мне данные. Однако, когда я пытаюсь вернуть эти значения в службу, они возвращаются Null. Я знаю, что это из-за async, и обратный вызов не ждет завершения HTTP-запроса.
Есть ли способ сделать эту работу?
Ответы
Ответ 1
Общей практикой является использование модуля 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]});
}
);
};
Вы также можете прочитать о других методах упорядочения обратного вызова здесь.
Ответ 2
Node.js - все о обратных вызовах. Если вызов API не является синхронным (редко и не должен выполняться), вы никогда не возвращаете значения из этих вызовов, а обратный вызов с результатом из метода обратного вызова или вызываете экспресс-метод res.send
Большая библиотека для вызова веб-запросов - request.js
Возьмем действительно простой пример вызова google. Используя 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);
}
})
});
В качестве альтернативы вы можете передать обратный вызов методу, который вызывает веб-запрос, и вызвать этот обратный вызов из этого метода:
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);
}
})
}
Ответ 3
Wait.for
https://github.com/luciotato/waitfor
Другие примеры ответов с использованием wait.for:
Пример из ответа Daniel (асинхронный), но используя 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);
});
}