Mengapa permintaan HTTP ini tidak berfungsi di AWS Lambda?

90

Saya memulai dengan AWS Lambda dan saya mencoba meminta layanan eksternal dari fungsi penangan saya. Menurut jawaban ini , permintaan HTTP seharusnya berfungsi dengan baik, dan saya belum menemukan dokumentasi yang mengatakan sebaliknya. (Faktanya, orang telah memposting kode yang menggunakan Twilio API untuk mengirim SMS .)

Kode penangan saya adalah:

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

dan saya melihat 4 baris berikut di log CloudWatch saya:

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

Saya mengharapkan baris lain di sana:

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

tapi itu hilang. Jika saya menggunakan bagian penting tanpa pembungkus penangan di node di mesin lokal saya, kode berfungsi seperti yang diharapkan.

Yang inputfile.txtsaya gunakan untuk invoke-asyncpanggilan adalah ini:

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

Sepertinya bagian dari kode penangan yang melakukan permintaan dilewati seluruhnya. Saya mulai dengan permintaan lib dan kembali menggunakan plainhttp untuk membuat contoh minimal. Saya juga mencoba meminta URL dari layanan yang saya kontrol untuk memeriksa log dan tidak ada permintaan yang masuk.

Saya benar-benar bingung. Apakah ada alasan Node dan / atau AWS Lambda tidak akan menjalankan permintaan HTTP?

awendt
sumber
Saya rasa hal ini mungkin disebabkan karena agen pengguna tidak ada dalam permintaan HTTP Anda.
Ma'moon Al-Akash
4
Pada saat penulisan, ini adalah pertanyaan teratas di forum Lambda di forum AWS. Itu membuatku gila dan juga sekelompok orang lain.
Nostradamus
@Nostradamus Saya menghargai umpan balik, koreksi, dan suara positif tambahan. Kirim mereka ke sini ;-)
awendt
1
Saya mencoba semuanya mulai dari contoh Twillo hingga beberapa contoh default yang dikirimkan dengan bundel contoh node Alexa dan juga metode context.done () Anda. http POST tidak berfungsi. Apakah mungkin untuk memposting contoh lengkap kode permintaan POST Anda?
chheplo

Jawaban:

80

Tentu saja, saya salah memahami masalahnya. Seperti yang dikatakan oleh AWS sendiri :

Bagi mereka yang menemukan nodej untuk pertama kalinya di Lambda, kesalahan umum adalah lupa bahwa callback dijalankan secara asinkron dan memanggil context.done()penangan asli saat Anda benar-benar ingin menunggu callback lain (seperti operasi S3.PUT) selesai, memaksa fungsi tersebut untuk mengakhiri dengan pekerjaannya tidak lengkap.

Saya menelepon context.done jauh sebelum panggilan balik untuk permintaan tersebut diaktifkan, menyebabkan penghentian fungsi saya sebelumnya.

Kode kerjanya adalah ini:

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

Pembaruan: mulai 2017 AWS tidak lagi menggunakan Nodejs 0.10 lama dan hanya run-time 4.3 yang lebih baru yang sekarang tersedia (fungsi lama harus diperbarui). Runtime ini memperkenalkan beberapa perubahan pada fungsi handler. Penangan baru sekarang memiliki 3 parameter.

function(event, context, callback)

Meskipun Anda masih akan menemukan succeed, donedan failpada parameter konteks, AWS menyarankan untuk menggunakan callbackfungsi sebagai gantinya atau nulldikembalikan secara default.

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

Dokumentasi lengkap dapat ditemukan di http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html

awendt
sumber
4
jadi, bagaimana Anda membuat kode penangan Anda berfungsi? saya mengerti adalah Anda perlu menghapus context.done () sehingga fungsi callback akan dipanggil. tapi kodemu masih tidak berfungsi untukku. :(
mabeiyi
3
The context.done()Panggilan perlu pindah ke callback (untuk sukses dan kasus error).
berakhir
2
belum memiliki masalah Anda, tetapi sebaiknya Anda diingat saat saya melanjutkan dengan lambda.
David
ada ide tentang bagaimana saya bisa memanggil api di sistem lokal saya dari Lambda?
Amit Kumar Ghosh
2
alat peraga untuk memperbarui pertanyaan 2015 dengan pembaruan 2017!
Ace
21

Contoh Kerja Sederhana dari permintaan Http menggunakan 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();
    });
}
smsivaprakaash
sumber
Terima kasih untuk ini. Ini adalah jawaban terbaik yang saya lihat di halaman ini pada tahun 2019, sekarang Lambda menggunakan sintaks await.
Taneem Tee
3
Ini membutuhkan waktu lebih dari satu jam untuk menemukan dan jawaban terbaik karena libs node-fetch requestdll tidak tersedia di Lambda secara default.
Alex C
Banyak kode contoh di luar sana yang tampaknya rusak sekarang. Ini berfungsi sebagai kode sampel pada Maret 2020, menggunakan AWS Lambda dengan Node.js 12.x
Muhammad Yussuf
Adakah yang bisa menjelaskan cara membuat permintaan POST dengan data di dalam fungsi lambda?
Pavindu
11

Ya, jawaban awendt sempurna. Saya hanya akan menunjukkan kode kerja saya ... Saya memiliki konteks. Berhasil ('Blah'); baris tepat setelah reqPost.end (); garis. Memindahkannya ke tempat saya tunjukkan di bawah menyelesaikan segalanya.

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

Saya menghadapi masalah ini pada versi Node 10.X. di bawah ini adalah kode kerja saya.

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();
};
Ameya Salagre
sumber
3

Saya memiliki masalah yang sama dan kemudian saya menyadari bahwa pemrograman di NodeJS sebenarnya berbeda dari Python atau Java karena berbasis JavaScript. Saya akan mencoba menggunakan konsep sederhana karena mungkin ada beberapa orang baru yang tertarik atau mungkin datang ke pertanyaan ini.

Mari kita lihat kode berikut:

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

Setiap kali Anda melakukan panggilan ke metode dalam paket http (1), itu dibuat sebagai acara dan acara ini membuatnya menjadi acara terpisah. Fungsi 'get' (2) sebenarnya adalah titik awal dari acara terpisah ini.

Sekarang, fungsi di (3) akan dijalankan dalam acara terpisah, dan kode Anda akan melanjutkan jalur eksekusi dan akan langsung melompat ke (4) dan menyelesaikannya, karena tidak ada lagi yang harus dilakukan.

Tetapi peristiwa yang dilakukan pada (2) masih berjalan di suatu tempat dan akan membutuhkan waktu yang menyenangkan untuk menyelesaikannya. Cukup aneh, bukan?. Ya, tidak. Ini adalah cara kerja NodeJS dan sangat penting bagi Anda untuk memahami konsep ini. Ini adalah tempat di mana Janji JavaScript datang untuk membantu.

Anda dapat membaca lebih lanjut tentang Janji JavaScript di sini . Singkatnya, Anda memerlukan JavaScript Promise untuk menjaga eksekusi kode sebaris dan tidak akan menelurkan utas baru / ekstra.

Sebagian besar paket NodeJS yang umum memiliki versi Promised dari API mereka, tetapi ada pendekatan lain seperti BlueBirdJS yang mengatasi masalah serupa.

Kode yang telah Anda tulis di atas dapat ditulis ulang secara longgar sebagai berikut.

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

Harap diperhatikan bahwa kode di atas tidak akan berfungsi secara langsung jika Anda akan mengimpornya di AWS Lambda. Untuk Lambda, Anda juga perlu mengemas modul dengan basis kode.

mmansoor.dll
sumber
Ya, janji! Meskipun saya akan mempertimbangkan untuk memindahkan context.done()panggilan ke finallymetode dirantai .
crftr
3

Saya telah menemukan banyak postingan di web tentang berbagai cara untuk melakukan permintaan, tetapi tidak ada yang benar-benar menunjukkan cara memproses respons secara sinkron di AWS Lambda.

Berikut adalah fungsi lambda Node 6.10.3 yang menggunakan permintaan https, mengumpulkan dan mengembalikan seluruh respons, dan meneruskan kontrol ke fungsi yang tidak terdaftar processBody dengan hasilnya. Saya yakin http dan https dapat dipertukarkan dalam kode ini.

Saya menggunakan modul utilitas async , yang lebih mudah dipahami oleh pemula. Anda harus memasukkannya ke AWS Stack untuk menggunakannya (saya merekomendasikan kerangka kerja tanpa server ).

Perhatikan bahwa data kembali dalam potongan, yang dikumpulkan dalam variabel global, dan terakhir callback dipanggil saat data telah enddiubah.

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

masukkan deskripsi gambar di sini

Tambahkan kode di atas di gateway API di bagian GET-Integration Request> bagian pemetaan.

Sher Singh
sumber
-14

Ya, sebenarnya ada banyak alasan mengapa Anda dapat mengakses suka AWS Lambda dan HTTP Endpoint.

Arsitektur AWS Lambda

Ini adalah layanan mikro. Berjalan di dalam EC2 dengan AMI Amazon Linux (Versi 3.14.26–24.46.amzn1.x86_64) dan berjalan dengan Node.js. Memori dapat berukuran 128mb dan 1gb. Saat sumber data memicu peristiwa, detailnya diteruskan ke fungsi Lambda sebagai parameternya.

Apa yang terjadi?

AWS Lambda dijalankan di dalam wadah, dan kodenya langsung diunggah ke wadah ini dengan paket atau modul. Misalnya, kami TIDAK PERNAH dapat melakukan SSH untuk mesin linux yang menjalankan fungsi lambda Anda. Satu-satunya hal yang dapat kami pantau adalah log, dengan CloudWatchLogs dan pengecualian yang berasal dari runtime.

AWS menangani peluncuran dan menghentikan kontainer untuk kami, dan cukup menjalankan kodenya. Jadi, meskipun Anda menggunakan require ('http'), ini tidak akan berfungsi, karena tempat kode ini dijalankan, tidak dibuat untuk ini.

jonathanbaraldi
sumber
5
Anda mungkin salah paham tentang masalah saya. Saya tahu tentang kode Lambda yang dijalankan dalam penampung, dan saya tahu saya tidak dapat mengakses mesin yang mendasarinya. Saya juga tidak mencoba masuk, kode saya mencoba untuk keluar, yaitu mengakses titik akhir eksternal, dan Lambda dapat melakukannya dengan cukup baik. Masalahnya adalah sesuatu yang sama sekali berbeda, seperti yang telah saya tunjukkan dalam jawaban saya sendiri.
berakhir