Bu HTTP isteği neden AWS Lambda'da çalışmıyor?


90

AWS Lambda'yı kullanmaya başladım ve işleyici işlevimden harici bir hizmet talep etmeye çalışıyorum. Bu yanıta göre , HTTP istekleri gayet iyi çalışmalı ve aksini söyleyen herhangi bir belge bulamadım. (Aslında insanlar SMS göndermek için Twilio API'sini kullanan bir kod yayınladılar .)

İşleyici kodum:

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

ve CloudWatch günlüklerimde aşağıdaki 4 satırı görüyorum:

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

Orada başka bir satır bekliyorum:

2015-02-11 07:38:06 UTC eb19c89d-b1c0-11e4-bceb-d310b88d37e2 Got response: 302

ama bu eksik. Yerel makinemdeki düğümde işleyici sarmalayıcı olmadan temel parçayı kullanıyorsam, kod beklendiği gibi çalışır.

inputfile.txtİçin kullanıyorum olduğunu invoke-asyncçağrısı şudur:

{
   "url":"http://www.google.com"
}

İşleyici kodunun isteği yapan kısmı tamamen atlanmış gibi görünüyor. Lib isteği ile başladım ve httpminimal bir örnek oluşturmak için Plain kullanmaya başladım . Ayrıca, günlükleri kontrol etmek için kontrol ettiğim bir hizmetin URL'sini istemeye çalıştım ve gelen hiçbir istek yok.

Tamamen şaşkına döndüm. Node ve / veya AWS Lambda'nın HTTP isteğini yürütmemesinin herhangi bir nedeni var mı?


Bunun HTTP isteğinizdeki eksik bir kullanıcı aracısından kaynaklanabileceğini düşünüyorum.
Ma'moon Al-Akash

4
Yazma sırasında bu, şu anda AWS forumlarının Lambda forumundaki en önemli sorudur. Bu beni delirtiyor ve ayrıca bir grup başka insanı da.
Nostradamus

@Nostradamus Ek geri bildirimler, düzeltmeler ve olumlu oylar için teşekkür ederim. Buraya gönderin ;-)
awendt

1
Twillo örneğinden Alexa düğüm örnek paketiyle birlikte gönderilen birkaç varsayılan örneğe ve ayrıca context.done () yönteminize kadar her şeyi denedim. http POST çalışmıyor. POST istek kodunuzun eksiksiz bir örneğini göndermek mümkün müdür?
chheplo

Yanıtlar:


80

Tabii ki sorunu yanlış anlıyordum. AWS'nin kendisinin belirttiği gibi :

Lambda'da nodej'lerle ilk kez karşılaşanlar için yaygın bir hata, geri aramaların eşzamansız olarak yürütüldüğünü unutmak ve context.done()gerçekten başka bir geri aramanın (S3.PUT işlemi gibi) tamamlanmasını beklemek istediğinizde orijinal işleyiciyi çağırmaktır . eksik çalışmasıyla sonlandırmak.

context.doneİstek için herhangi bir geri aramadan çok önce arıyordum ve bu da işlevimin vaktinden önce sonlandırılmasına neden oldu.

Çalışma kodu şudur:

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

Güncelleme: 2017'den itibaren AWS, eski Nodejs 0.10'u kullanımdan kaldırmıştır ve artık yalnızca daha yeni 4.3 çalışma zamanı mevcuttur (eski işlevler güncellenmelidir). Bu çalışma zamanı, işleyici işlevine bazı değişiklikler getirdi. Yeni işleyicinin artık 3 parametresi vardır.

function(event, context, callback)

Hala bulacaksınız rağmen succeed, doneve failbağlam parametre üzerinde, AWS kullanmayı önermek callbackyerine işlev veya nullvarsayılan olarak döndürülür.

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

Tam dokümantasyon http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html adresinde bulunabilir.


4
Peki, işleyici kodunuzun çalışmasını nasıl sağlarsınız? anladığım kadarıyla geri arama işlevinin çağrılması için context.done () öğesini kaldırmanız gerekiyor. ama kodunuz hala benim için çalışmıyor. :(
mabeiyi

3
context.done()Çağrı (başarı ve hata durumu için) geri aramaları taşındı gerekmektedir.
awendt

2
henüz sorununuz yok, ancak lambda ile ilerlerken akılda tutulması harika.
David

Yerel sistemimde Lambda'dan bir api'yi nasıl çağırabilirim?
Amit Kumar Ghosh

2
2015 sorusunu 2017 güncellemeleriyle güncellemek için aksesuarlar!
Ace

21

Düğüm kullanan Http isteğinin Basit Çalışma Örneği.

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();
    });
}

Bunun için teşekkür ederim. Lambda artık await sözdizimini kullandığı için 2019'da bu sayfada gördüğüm en iyi cevap bu.
Taneem Tee

3
Kitaplar node-fetch requestvb. Varsayılan olarak Lambda'da bulunmadığından bu, en iyi cevabı bulmam bir saatten fazla sürdü .
Alex C

Dışarıdaki örnek kodun çoğu şimdi bozuk görünüyor. Bu, Mart 2020 itibarıyla, AWS Lambda'yı Node.js 12.x ile kullanarak çalışan örnek koddur
Muhammad Yussuf

Lambda fonksiyonları içindeki verilerle POST isteklerinin nasıl yapılacağını birisi açıklayabilir mi?
Pavindu

11

Evet, awendt cevabı mükemmel. Sadece çalışma kodumu göstereceğim ... context.succeed ('Blah'); reqPost.end () 'den hemen sonraki satır ; hat. Aşağıda gösterdiğim yere taşımak her şeyi çözdü.

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();
};

4

Bu sorunla Node 10.X sürümünde karşılaştım. aşağıda çalışma kodum var.

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();
};

3

Aynı problemi yaşadım ve sonra NodeJS'deki programlamanın JavaScript tabanlı olduğu için Python veya Java'dan farklı olduğunu fark ettim. Bu soruya ilgi duyacak veya gelebilecek birkaç yeni insan olabileceği için basit kavramları kullanmaya çalışacağım.

Aşağıdaki koda bakalım:

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)
}

Http paketinde (1) bir yönteme her çağrı yaptığınızda, olay olarak yaratılır ve bu olay onu ayrı bir olay alır. 'Get' işlevi (2) aslında bu ayrı olayın başlangıç ​​noktasıdır.

Şimdi, (3) 'teki işlev ayrı bir olayda yürütülecek ve kodunuz yolu yürütmeye devam edecek ve doğrudan (4)' e atlayacak ve bitirecek, çünkü yapacak başka bir şey yok.

Ancak (2) 'de ateşlenen olay hala bir yerde yürütülüyor ve bitirmek kendi tatlı zamanını alacak. Oldukça tuhaf, değil mi? Hayır, değil. NodeJS bu şekilde çalışır ve oldukça önemlidir, kafanızı bu konseptin etrafına sarmanız çok önemlidir. JavaScript Promises'in yardıma geldiği yer burasıdır.

JavaScript Promises hakkında daha fazla bilgiyi okuyabilir burada . Özetle, kodun yürütülmesini satır içinde tutmak için bir JavaScript Sözüne ihtiyacınız olacak ve yeni / fazladan iş parçacıkları üretmeyeceksiniz.

Yaygın NodeJS paketlerinin çoğu, API'lerinin Söz Verilmiş bir sürümüne sahiptir, ancak BlueBirdJS gibi benzer sorunu ele alan başka yaklaşımlar da vardır.

Yukarıda yazmış olduğunuz kod aşağıdaki gibi gevşek bir şekilde yeniden yazılabilir.

'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);
};

AWS Lambda'ya aktaracaksanız yukarıdaki kodun doğrudan çalışmayacağını lütfen unutmayın. Lambda için modülleri kod tabanıyla da paketlemeniz gerekecektir.


Evet, sözler! context.done()Çağrıyı zincirleme bir finallyyönteme taşımayı düşünürdüm .
crftr

3

Web'de, isteği yapmanın çeşitli yollarıyla ilgili çok sayıda gönderi buldum, ancak hiçbiri yanıtın AWS Lambda'da eşzamanlı olarak nasıl işleneceğini göstermiyor.

İşte bir https isteği kullanan, yanıtın tüm gövdesini toplayan ve döndüren processBodyve sonuçlarla birlikte denetimi listelenmemiş bir işleve geçiren bir Düğüm 6.10.3 lambda işlevi . Bu kodda http ve https'nin birbiriyle değiştirilebilir olduğuna inanıyorum.

Yeni başlayanlar için anlaşılması daha kolay olan zaman uyumsuz yardımcı program modülünü kullanıyorum . Bunu kullanmak için AWS Stack'inize aktarmanız gerekir ( sunucusuz çerçeveyi öneririm ).

Verilerin, küresel bir değişkende toplanan parçalar halinde geri geldiğini ve son olarak, veriler düzenlendiğinde geri çağırmanın çağrıldığını unutmayın end.

'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);
        });
    }
};

0

görüntü açıklamasını buraya girin

Yukarıdaki kodu GET-Entegrasyon İsteği> eşleme bölümü altındaki API ağ geçidine ekleyin.


-14

Evet, AWS Lambda like ve HTTP Endpoint'e erişebilmenizin aslında birçok nedeni var.

AWS Lambda'nın mimarisi

Bu bir mikro hizmet. EC2 içinde Amazon Linux AMI (Sürüm 3.14.26–24.46.amzn1.x86_64) ile çalışır ve Node.js ile çalışır. Hafıza 128mb ve 1gb olabilir. Veri kaynağı olayı tetiklediğinde, ayrıntılar bir Lambda işlevine parametre olarak aktarılır.

Ne oluyor?

AWS Lambda çalıştırması bir kapsayıcı içinde gerçekleşir ve kod, paketler veya modüllerle doğrudan bu kapsayıcıya yüklenir. Örneğin, lambda işlevinizi çalıştıran linux makinesi için ASLA SSH yapamayız. İzleyebileceğimiz tek şey, CloudWatchLogs ile birlikte günlükler ve çalışma zamanından gelen istisna.

AWS bizim için kapsayıcıları başlatıp sonlandırır ve sadece kodu çalıştırın. Yani, require ('http') kullansanız bile, işe yaramayacak çünkü bu kodun çalıştığı yer bunun için yapılmadı.


5
Sorunumu yanlış anlamış olabilirsiniz. Lambda kodunun bir kapsayıcıda çalıştırıldığını biliyorum ve temeldeki makineye erişemeyeceğimi biliyorum. Ben de içeri girmeye çalışmıyorum, kodum dışarı çıkmaya çalışıyor, yani harici uç noktalara erişiyor ve Lambda bunu oldukça iyi yapıyor. Kendi cevabımda da belirttiğim gibi sorun tamamen farklı bir konuydu.
awendt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.