Je commence avec AWS Lambda et j'essaie de demander un service externe à ma fonction de gestionnaire. Selon cette réponse , les requêtes HTTP devraient fonctionner correctement, et je n'ai trouvé aucune documentation indiquant le contraire. (En fait, des gens ont publié du code qui utilise l'API Twilio pour envoyer des SMS .)
Mon code de gestionnaire est:
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);
}
et je vois les 4 lignes suivantes dans mes journaux 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
Je m'attendrais à une autre ligne là-dedans:
2015-02-11 07:38:06 UTC eb19c89d-b1c0-11e4-bceb-d310b88d37e2 Got response: 302
mais cela manque. Si j'utilise la partie essentielle sans le wrapper de gestionnaire dans le nœud sur ma machine locale, le code fonctionne comme prévu.
Le que inputfile.txt
j'utilise pour l' invoke-async
appel est le suivant:
{
"url":"http://www.google.com"
}
Il semble que la partie du code du gestionnaire qui exécute la requête soit entièrement ignorée. J'ai commencé avec la librairie de requête et je suis revenu à l'utilisation de plain http
pour créer un exemple minimal. J'ai également essayé de demander une URL d'un service que je contrôle pour vérifier les journaux et il n'y a aucune demande entrant.
Je suis totalement perplexe. Y a-t-il une raison pour laquelle Node et / ou AWS Lambda n'exécuteraient pas la requête HTTP?
Réponses:
Bien sûr, je ne comprenais pas le problème. Comme le dit AWS lui-même :
J'appelais
context.done
bien avant que les rappels pour la demande ne soient déclenchés, provoquant la fin de ma fonction à l'avance.Le code de travail est le suivant:
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); }
Mise à jour: à partir de 2017, AWS a déprécié l'ancien Nodejs 0.10 et seul le plus récent environnement d'exécution 4.3 est désormais disponible (les anciennes fonctions doivent être mises à jour). Ce runtime a introduit quelques modifications dans la fonction de gestionnaire. Le nouveau gestionnaire a maintenant 3 paramètres.
function(event, context, callback)
Bien que vous trouviez toujours le
succeed
,done
etfail
sur le paramètre de contexte, AWS suggère d'utiliser lacallback
fonction à la place ounull
est renvoyé par défaut.callback(new Error('failure')) // to return error callback(null, 'success msg') // to return ok
La documentation complète peut être trouvée sur http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
la source
context.done()
appel doit être déplacé dans les rappels (en cas de succès et d'erreur).Exemple de travail simple de requête Http utilisant 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(); }); }
la source
node-fetch
request
etc. ne sont pas disponibles sur Lambda par défaut.Ouais, toute réponse est parfaite. Je vais juste montrer mon code de travail ... J'ai eu le context.succeed ('Blah'); ligne juste après le reqPost.end (); ligne. Le déplacer là où je montre ci-dessous a tout résolu.
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(); };
la source
J'ai rencontré ce problème sur la version Node 10.X. ci-dessous est mon code de travail.
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(); };
la source
J'ai eu le même problème, puis j'ai réalisé que la programmation dans NodeJS est en fait différente de Python ou Java car elle est basée sur JavaScript. Je vais essayer d'utiliser des concepts simples car il y a peut-être quelques nouvelles personnes qui seraient intéressées ou pourraient venir à cette question.
Regardons le code suivant:
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) }
Chaque fois que vous appelez une méthode dans le package http (1), elle est créée en tant qu'événement et cet événement obtient un événement distinct. La fonction 'get' (2) est en fait le point de départ de cet événement séparé.
Maintenant, la fonction en (3) s'exécutera dans un événement séparé, et votre code continuera d'exécuter le chemin et passera directement à (4) et le terminera, car il n'y a plus rien à faire.
Mais l'événement déclenché sur (2) est toujours en cours d'exécution quelque part et cela prendra son temps pour se terminer. Assez bizarre, non?. Eh bien, non, ce n'est pas le cas. C'est ainsi que fonctionne NodeJS et il est assez important de comprendre ce concept. C'est ici que les promesses JavaScript viennent vous aider.
Vous pouvez en savoir plus sur les promesses JavaScript ici . En un mot, vous auriez besoin d'une promesse JavaScript pour maintenir l'exécution du code en ligne et ne créera pas de nouveaux threads / supplémentaires.
La plupart des packages NodeJS courants ont une version Promised de leur API disponible, mais il existe d'autres approches comme BlueBirdJS qui résolvent le problème similaire.
Le code que vous aviez écrit ci-dessus peut être librement réécrit comme suit.
'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); };
Veuillez noter que le code ci-dessus ne fonctionnera pas directement si vous l'importez dans AWS Lambda. Pour Lambda, vous devrez également empaqueter les modules avec la base de code.
la source
context.done()
appel dans unefinally
méthode en chaîne .J'ai trouvé de nombreux articles sur le Web sur les différentes façons de faire la demande, mais aucun ne montre réellement comment traiter la réponse de manière synchrone sur AWS Lambda.
Voici une fonction lambda Node 6.10.3 qui utilise une requête https, collecte et retourne le corps complet de la réponse et transmet le contrôle à une fonction non répertoriée
processBody
avec les résultats. Je crois que http et https sont interchangeables dans ce code.J'utilise le module utilitaire async , qui est plus facile à comprendre pour les débutants. Vous devrez pousser cela vers votre AWS Stack pour l'utiliser (je recommande le framework sans serveur ).
Notez que les données reviennent par blocs, qui sont rassemblés dans une variable globale, et enfin le rappel est appelé lorsque les données ont été
end
éditées.'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); }); } };
la source
Ajoutez le code ci-dessus dans la passerelle API sous GET-Integration Request> section de mappage.
la source
Oui, il existe en fait de nombreuses raisons pour lesquelles vous pouvez accéder à AWS Lambda comme et HTTP Endpoint.
L'architecture d'AWS Lambda
C'est un microservice. Exécution dans EC2 avec Amazon Linux AMI (version 3.14.26–24.46.amzn1.x86_64) et s'exécute avec Node.js. La mémoire peut être comprise entre 128 Mo et 1 Go. Lorsque la source de données déclenche l'événement, les détails sont transmis à une fonction Lambda en tant que paramètre.
Qu'est-ce qui se passe?
AWS Lambda s'exécute dans un conteneur et le code est directement téléchargé dans ce conteneur avec des packages ou des modules. Par exemple, nous ne pouvons JAMAIS faire de SSH pour la machine Linux exécutant votre fonction lambda. Les seules choses que nous pouvons surveiller sont les journaux, avec CloudWatchLogs et l'exception provenant du runtime.
AWS s'occupe du lancement et de l'arrêt des conteneurs pour nous, et exécute simplement le code. Donc, même si vous utilisez require ('http'), cela ne fonctionnera pas, car l'endroit où ce code s'exécute n'a pas été fait pour cela.
la source