Rozpoczynam pracę z AWS Lambda i próbuję zażądać usługi zewnętrznej z mojej funkcji obsługi. Zgodnie z tą odpowiedzią żądania HTTP powinny działać dobrze, a nie znalazłem żadnej dokumentacji, która mówi inaczej. (W rzeczywistości ludzie opublikowali kod, który używa interfejsu API Twilio do wysyłania wiadomości SMS ).
Mój kod obsługi to:
var http = require('http');
exports.handler = function(event, context) {
console.log('start request to ' + event.url)
http.get(event.url, function(res) {
console.log("Got response: " + res.statusCode);
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
console.log('end request to ' + event.url)
context.done(null);
}
i widzę następujące 4 wiersze w moich dziennikach CloudWatch:
2015-02-11 07:38:06 UTC START RequestId: eb19c89d-b1c0-11e4-bceb-d310b88d37e2
2015-02-11 07:38:06 UTC eb19c89d-b1c0-11e4-bceb-d310b88d37e2 start request to http://www.google.com
2015-02-11 07:38:06 UTC eb19c89d-b1c0-11e4-bceb-d310b88d37e2 end request to http://www.google.com
2015-02-11 07:38:06 UTC END RequestId: eb19c89d-b1c0-11e4-bceb-d310b88d37e2
Spodziewałbym się tam kolejnej linii:
2015-02-11 07:38:06 UTC eb19c89d-b1c0-11e4-bceb-d310b88d37e2 Got response: 302
ale tego brakuje. Jeśli używam podstawowej części bez opakowania programu obsługi w węźle na moim komputerze lokalnym, kod działa zgodnie z oczekiwaniami.
inputfile.txt
Używam jest dla invoke-async
połączenia jest następujący:
{
"url":"http://www.google.com"
}
Wygląda na to, że część kodu obsługi, która wykonuje żądanie, jest całkowicie pomijana. Zacząłem od żądania lib i wróciłem do używania zwykłego http
do tworzenia minimalnego przykładu. Próbowałem również zażądać adresu URL usługi, którą kontroluję, aby sprawdzić dzienniki, ale nie przychodzą żadne żądania.
Jestem totalnie zaskoczony. Czy jest jakiś powód, dla którego Node i / lub AWS Lambda nie wykonałyby żądania HTTP?
Odpowiedzi:
Oczywiście źle zrozumiałem problem. Jak ujął to AWS :
I wołał
context.done
drogę zanim jakiekolwiek wywołania zwrotne na żądanie zwolniony, powodując zakończenie mojej funkcji z wyprzedzeniem.Działający kod jest następujący:
var http = require('http'); exports.handler = function(event, context) { console.log('start request to ' + event.url) http.get(event.url, function(res) { console.log("Got response: " + res.statusCode); context.succeed(); }).on('error', function(e) { console.log("Got error: " + e.message); context.done(null, 'FAILURE'); }); console.log('end request to ' + event.url); }
Aktualizacja: począwszy od 2017 AWS wycofał starą wersję Nodejs 0.10 i jest teraz dostępna tylko nowsza wersja 4.3 (stare funkcje powinny zostać zaktualizowane). W tym środowisku uruchomieniowym wprowadzono pewne zmiany w funkcji obsługi. Nowa obsługa ma teraz 3 parametry.
function(event, context, callback)
Chociaż można jeszcze znaleźć
succeed
,done
afail
na parametr kontekstowego AWS Proponuję używaćcallback
zamiast funkcji lubnull
zwracane jest domyślnie.callback(new Error('failure')) // to return error callback(null, 'success msg') // to return ok
Pełną dokumentację można znaleźć pod adresem http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
źródło
context.done()
Wezwanie musi być przeniesiona do wywołania zwrotne (dla sukcesu i przypadku błędu).Prosty przykład roboczy żądania HTTP przy użyciu node.
const http = require('https') exports.handler = async (event) => { return httprequest().then((data) => { const response = { statusCode: 200, body: JSON.stringify(data), }; return response; }); }; function httprequest() { return new Promise((resolve, reject) => { const options = { host: 'jsonplaceholder.typicode.com', path: '/todos', port: 443, method: 'GET' }; const req = http.request(options, (res) => { if (res.statusCode < 200 || res.statusCode >= 300) { return reject(new Error('statusCode=' + res.statusCode)); } var body = []; res.on('data', function(chunk) { body.push(chunk); }); res.on('end', function() { try { body = JSON.parse(Buffer.concat(body).toString()); } catch(e) { reject(e); } resolve(body); }); }); req.on('error', (e) => { reject(e.message); }); // send the request req.end(); }); }
źródło
node-fetch
request
itp. Nie są domyślnie dostępne w Lambdzie.Tak, dobra odpowiedź jest idealna. Pokażę tylko mój działający kod ... Miałem kontekst. Powodzenie ('Bla'); linia tuż po reqPost.end (); linia. Przeniesienie go do miejsca, które pokazuję poniżej, rozwiązało wszystko.
console.log('GW1'); var https = require('https'); exports.handler = function(event, context) { var body=''; var jsonObject = JSON.stringify(event); // the post options var optionspost = { host: 'the_host', path: '/the_path', method: 'POST', headers: { 'Content-Type': 'application/json', } }; var reqPost = https.request(optionspost, function(res) { console.log("statusCode: ", res.statusCode); res.on('data', function (chunk) { body += chunk; }); context.succeed('Blah'); }); reqPost.write(jsonObject); reqPost.end(); };
źródło
Napotkałem ten problem w wersji Node 10.X. poniżej jest mój działający kod.
const https = require('https'); exports.handler = (event,context,callback) => { let body=''; let jsonObject = JSON.stringify(event); // the post options var optionspost = { host: 'example.com', path: '/api/mypath', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'blah blah', } }; let reqPost = https.request(optionspost, function(res) { console.log("statusCode: ", res.statusCode); res.on('data', function (chunk) { body += chunk; }); res.on('end', function () { console.log("Result", body.toString()); context.succeed("Sucess") }); res.on('error', function () { console.log("Result Error", body.toString()); context.done(null, 'FAILURE'); }); }); reqPost.write(jsonObject); reqPost.end(); };
źródło
Miałem ten sam problem, a potem zdałem sobie sprawę, że programowanie w NodeJS jest w rzeczywistości inne niż Python czy Java, ponieważ opiera się na JavaScript. Spróbuję użyć prostych pojęć, ponieważ może być kilka nowych osób, które byłyby zainteresowane lub mogą przyjść do tego pytania.
Spójrzmy na następujący kod:
var http = require('http'); // (1) exports.handler = function(event, context) { console.log('start request to ' + event.url) http.get(event.url, // (2) function(res) { //(3) console.log("Got response: " + res.statusCode); context.succeed(); }).on('error', function(e) { console.log("Got error: " + e.message); context.done(null, 'FAILURE'); }); console.log('end request to ' + event.url); //(4) }
Ilekroć wywołujesz metodę w pakiecie http (1), jest ona tworzona jako zdarzenie, a to zdarzenie otrzymuje osobne zdarzenie. Funkcja „get” (2) jest właściwie punktem wyjścia tego oddzielnego zdarzenia.
Teraz funkcja w (3) będzie wykonywana w osobnym zdarzeniu, a twój kod będzie kontynuował wykonywanie ścieżki, a następnie skoczy do (4) i zakończy to, ponieważ nie ma nic więcej do zrobienia.
Ale zdarzenie wystrzelone w (2) wciąż gdzieś się odbywa i jego zakończenie zajmie swój własny słodki czas. Dość dziwne, prawda? Cóż, nie jest. Tak działa NodeJS i bardzo ważne jest, abyś owinął głowę wokół tej koncepcji. Jest to miejsce, w którym z pomocą przychodzą obietnice JavaScript.
Możesz przeczytać więcej o obietnicach JavaScript tutaj . Krótko mówiąc, potrzebowałbyś Obietnicy JavaScript, aby utrzymać wykonywanie kodu w tekście i nie powodować powstawania nowych / dodatkowych wątków.
Większość popularnych pakietów NodeJS ma dostępną wersję Promised ich API, ale istnieją inne podejścia, takie jak BlueBirdJS, które rozwiązują podobny problem.
Kod, który napisałeś powyżej, można luźno przepisać w następujący sposób.
'use strict'; console.log('Loading function'); var rp = require('request-promise'); exports.handler = (event, context, callback) => { var options = { uri: 'https://httpbin.org/ip', method: 'POST', body: { }, json: true }; rp(options).then(function (parsedBody) { console.log(parsedBody); }) .catch(function (err) { // POST failed... console.log(err); }); context.done(null); };
Pamiętaj, że powyższy kod nie będzie działał bezpośrednio, jeśli zaimportujesz go do AWS Lambda. W przypadku Lambda będziesz musiał również spakować moduły z bazą kodu.
źródło
context.done()
połączenia dofinally
metody łańcuchowej .Znalazłem wiele postów w Internecie na temat różnych sposobów realizacji żądania, ale żaden z nich nie pokazuje, jak synchronicznie przetwarzać odpowiedź na AWS Lambda.
Oto funkcja lambda Node 6.10.3, która używa żądania https, zbiera i zwraca pełną treść odpowiedzi oraz przekazuje kontrolę do funkcji spoza listy
processBody
wraz z wynikami. Uważam, że http i https są wymienne w tym kodzie.Używam modułu narzędziowego Async , który jest łatwiejszy do zrozumienia dla początkujących. Będziesz musiał przesłać to do swojego stosu AWS, aby go użyć (polecam framework bezserwerowy ).
Zwróć uwagę, że dane wracają w kawałkach, które są gromadzone w zmiennej globalnej, a na koniec wywołanie zwrotne jest wywoływane, gdy dane
end
ulegną zmianie.'use strict'; const async = require('async'); const https = require('https'); module.exports.handler = function (event, context, callback) { let body = ""; let countChunks = 0; async.waterfall([ requestDataFromFeed, // processBody, ], (err, result) => { if (err) { console.log(err); callback(err); } else { const message = "Success"; console.log(result.body); callback(null, message); } }); function requestDataFromFeed(callback) { const url = 'https://put-your-feed-here.com'; console.log(`Sending GET request to ${url}`); https.get(url, (response) => { console.log('statusCode:', response.statusCode); response.on('data', (chunk) => { countChunks++; body += chunk; }); response.on('end', () => { const result = { countChunks: countChunks, body: body }; callback(null, result); }); }).on('error', (err) => { console.log(err); callback(err); }); } };
źródło
Dodaj powyższy kod w bramie API w sekcji GET-Integration Request> mapping.
źródło
Tak, w rzeczywistości istnieje wiele powodów, dla których możesz uzyskać dostęp do AWS Lambda like i HTTP Endpoint.
Architektura AWS Lambda
To mikrousługa. Działa w EC2 z Amazon Linux AMI (wersja 3.14.26–24.46.amzn1.x86_64) i działa z Node.js. Pamięć może mieć od 128 MB do 1 GB. Gdy źródło danych wyzwala zdarzenie, szczegóły są przekazywane do funkcji Lambda jako parametr.
Co się stało?
AWS Lambda działa w kontenerze, a kod jest bezpośrednio przesyłany do tego kontenera z pakietami lub modułami. Na przykład, NIGDY nie możemy wykonać SSH dla maszyny linux, na której działa twoja funkcja lambda. Jedyne, co możemy monitorować, to logi, z CloudWatchLogs i wyjątek pochodzący ze środowiska wykonawczego.
AWS zajmie się uruchamianiem i zamykaniem kontenerów za nas, a po prostu uruchom kod. Więc nawet jeśli użyjesz require ('http'), to nie zadziała, ponieważ miejsce, w którym działa ten kod, nie zostało do tego stworzone.
źródło