Dlaczego to żądanie HTTP nie działa na AWS Lambda?

Zaczynam pracę z AWS Lambda i próbuję poprosić o zewnętrzną usługę z mojej funkcji obsługi. Zgodnie z ta odpowiedź , żądania HTTP powinny działać dobrze, i nie znalazłem żadnej dokumentacji, która mówi inaczej. (W rzeczywistości ludzie opublikowali kod , który używa API Twilio do wysyłania wiadomości SMS.)

Mój kod 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 linijki w moich logach 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ę kolejnej linijki tam:

2015-02-11 07:38:06 UTC eb19c89d-b1c0-11e4-bceb-d310b88d37e2 Got response: 302
Ale tego brakuje. Jeśli używam zasadniczej części bez owijki obsługi w węźle na mojej lokalnej maszynie, kod działa zgodnie z oczekiwaniami.

inputfile.txt używam do wywołania invoke-async jest to:

{
   "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 request lib i wróciłem do używania zwykłego http, aby stworzyć minimalny przykład. Próbowałem również poprosić o adres URL usługi I Kontrola, aby sprawdzić dzienniki i nie ma żadnych żądań.

Jestem totalnie zakłopotany. Czy Jest jakiś powód, dla którego Node i / lub AWS Lambda nie wykonałyby żądania HTTP?
Author: Community, 2015-02-11

8 answers

Oczywiście, źle zrozumiałem problem. Jak to ujęli sami AWS :

Dla tych, którzy po raz pierwszy spotykają nodejsa w Lambdzie, wspólnej błąd polega na zapominaniu, że wywołania zwrotne wykonują się asynchronicznie i wywołują context.done() w oryginalnym opiekunie, kiedy naprawdę chciałeś czekać dla innego wywołania zwrotnego (takiego jak S3.Operacji) do zakończenia, wymuszając funkcja zakończenia jej pracy jest niekompletna.

I was calling context.done way przed odwołaniem żądania wywołane, powodując zakończenie mojej funkcji z wyprzedzeniem.

Kod roboczy 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);
}

Update: począwszy od 2017 r. AWS zdezaktualizował Stary Nodejs 0.10 i tylko nowszy czas uruchamiania 4.3 jest teraz dostępny (stare funkcje powinny być aktualizowane). To środowisko uruchomieniowe wprowadziło pewne zmiany w funkcji obsługi. Nowy handler ma teraz 3 parametry.

function(event, context, callback)

Chociaż nadal znajdziesz succeed, done i fail na parametr kontekstowy, AWS sugeruje użycie funkcji callback zamiast tego lub null jest zwracane domyślnie.

callback(new Error('failure')) // to return error
callback(null, 'success msg') // to return ok

Pełna dokumentacja znajduje się na stronie http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html

 81
Author: awendt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-31 20:30:08

Prosty roboczy przykład żądania Http przy użyciu węzła.

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();
    });
}
 24
Author: smsivaprakaash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-12 15:48:46

Tak, odpowiedź awendt jest idealna. Pokażę tylko mój kod roboczy... Miałem kontekst.succeed ('Blah'); linia tuż za reqpostem .end (); line. Przeniesienie go do miejsca, w którym 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();
};
 11
Author: imTachu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 00:25:20

Miałem do czynienia z tym problemem na węźle 10.Wersja X. poniżej znajduje się mój kod roboczy.

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();
};
 5
Author: Ameya Salagre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-08 07:15:30

Miałem ten sam problem i wtedy zdałem sobie sprawę, że programowanie w NodeJS jest tak naprawdę inne niż Python czy Java, ponieważ opiera się na JavaScript. Postaram się 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)
}

Za każdym razem, gdy wywołujesz metodę w http package (1), jest ona tworzona jako event i to zdarzenie otrzymuje osobne Zdarzenie. Funkcja' get ' (2) jest w rzeczywistości punkt wyjścia tego osobnego wydarzenia.

Teraz funkcja w (3) będzie wykonywana w osobnym zdarzeniu, a Twój kod będzie kontynuował ją wykonując ścieżkę i przeskoczy prosto do (4) i zakończy ją, ponieważ nie ma nic więcej do zrobienia.

Ale zdarzenie wywołane w (2) nadal gdzieś się wykonuje i zajmie mu to trochę czasu. Dziwne, prawda ?. Nie, Nie jest. W ten sposób działa NodeJS i jego bardzo ważne, że owijasz głowę wokół tej koncepcji. To jest miejsce, w którym obietnice JavaScript przychodzą z pomocą.

Możesz przeczytać więcej o obietnicach JavaScript tutaj . W skrócie, potrzebujesz obietnicy JavaScript, aby zachować wykonywanie kodu inline i nie pojawią się nowe / dodatkowe wątki.

Większość popularnych pakietów NodeJS ma obiecaną wersję swojego API, ale istnieją inne podejścia, takie jak BlueBirdJS, które rozwiązują podobny problem.

Kod, który napisałeś powyżej, może być luźno ponownie napisane 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 w AWS Lambda. W przypadku Lambda konieczne będzie również spakowanie modułów z bazą kodu.

 3
Author: mmansoor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-03 14:02:36

Znalazłem wiele postów w Internecie na różne sposoby wykonania żądania, ale żaden, który faktycznie pokazuje, jak przetworzyć odpowiedź synchronicznie na AWS Lambda.

Oto Node 6.10.3 funkcja lambda, która wykorzystuje żądanie https, zbiera i zwraca całą treść odpowiedzi i przekazuje kontrolę do nienotowanej funkcji processBody z wynikami. Uważam, że http i https są wymienne w tym kodzie.

Używam async utility module , co jest łatwiejsze aby zrozumieć dla początkujących. Aby go użyć, musisz wcisnąć go do swojego stosu AWS (polecam framework serverless).

Zauważ, że dane wracają w kawałkach, które są gromadzone w zmiennej globalnej, a na koniec wywołanie zwrotne jest wywoływane, gdy dane mają ended.

'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);
        });
    }
};
 3
Author: Zodman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 04:44:51

Tutaj wpisz opis obrazka

Dodaj powyższy kod w bramie API w sekcji GET-Integration Request> mapping.

 0
Author: Sher Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-19 11:25:27

Tak, Istnieje wiele powodów, dla których możesz uzyskać dostęp do punktu końcowego AWS Lambda like I http.

Architektura AWS Lambda

To mikrousługa. Działa wewnątrz EC2 z Amazon Linux AMI (Wersja 3.14.26-24.46.amzn1x86_64) i działa z Node.js. Pamięć może mieć 128MB i 1gb. Gdy źródło danych uruchamia Zdarzenie, szczegóły są przekazywane do funkcji Lambda jako parametr.

Co się stało?

AWS Lambda run ' s inside a container, and the code jest przesyłany bezpośrednio do tego kontenera z pakietami lub modułami. Na przykład, nigdy nie możemy wykonać SSH dla linuksowego komputera z funkcją lambda. Jedyne, co możemy monitorować, to logi, z Cloudwatchlogami i wyjątkiem pochodzącym z runtime.

AWS zajmie się uruchomieniem i zakończeniem kontenerów za nas, po prostu uruchom kod. Tak więc, nawet jeśli używasz require ('http'), to nie zadziała, ponieważ miejsce, w którym działa ten kod, nie zostało do tego stworzone.

 -15
Author: jonathanbaraldi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-18 03:42:37