이 HTTP 요청이 AWS Lambda에서 작동하지 않는 이유는 무엇입니까?


89

AWS Lambda를 시작하고 핸들러 함수에서 외부 서비스를 요청하려고합니다. 이 답변 에 따르면 HTTP 요청은 제대로 작동해야하며 달리 언급 된 문서를 찾지 못했습니다. (사실 사람들은 Twilio API를 사용하여 SMS를 보내는 코드를 게시했습니다 .)

내 핸들러 코드는 다음과 같습니다.

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

내 CloudWatch 로그에 다음 4 줄이 표시됩니다.

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

나는 거기에 다른 줄을 기대합니다.

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

그러나 그것은 누락되었습니다. 로컬 컴퓨터의 노드에서 핸들러 래퍼없이 필수 부분을 사용하는 경우 코드가 예상대로 작동합니다.

inputfile.txt을 위해 내가 사용은 invoke-async호출이 있습니다 :

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

요청을 수행하는 핸들러 코드의 일부가 완전히 건너 뛴 것 같습니다. 요청 lib로 시작 하여 일반 사용으로 돌아갔습니다.http 하여 최소한의 예제를 만들기 위해 을 사용하는 것으로 . 또한 로그를 확인하기 위해 제어하는 ​​서비스의 URL을 요청하려고했지만 들어오는 요청이 없습니다.

나는 완전히 어리둥절합니다. Node 및 / 또는 AWS Lambda가 HTTP 요청을 실행하지 않는 이유가 있습니까?


HTTP 요청에 사용자 에이전트가 누락 되었기 때문일 수 있습니다.
Ma'moon Al-Akash

4
글을 쓰는 시점에서 이것은 현재 AWS 포럼의 Lambda 포럼에서 가장 인기있는 질문입니다. 그것은 나를 미치게 만들고 다른 많은 사람들도 마찬가지입니다.
Nostradamus 2015 년

@Nostradamus 추가 피드백, 수정 및 찬성 투표에 감사드립니다. ;-) 여기에 보내기
awendt

1
Twillo 예제부터 Alexa 노드 예제 번들 및 context.done () 메서드와 함께 제공되는 몇 가지 기본 예제에 이르기까지 모든 것을 시도했습니다. http POST가 작동하지 않습니다. POST 요청 코드의 전체 샘플을 게시 할 수 있습니까?
chheplo

답변:


79

물론 나는 문제를 오해하고 있었다. AWS 자체가 말했듯이 :

Lambda에서 처음으로 nodejs를 접하는 경우 일반적인 오류는 콜백이 비동기 적으로 실행된다는 사실을 잊고 context.done()실제로 다른 콜백 (예 : S3.PUT 작업)이 완료 될 때까지 기다리려고 할 때 원래 핸들러를 호출 하여 함수를 강제 실행하는 것입니다. 불완전한 작업으로 종료됩니다.

context.done요청에 대한 콜백이 발생하기 전에 호출 하여 미리 함수가 종료되었습니다.

작동 코드는 다음과 같습니다.

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

업데이트 : 2017 년부터 AWS는 이전 Nodejs 0.10을 더 이상 사용하지 않으며 이제 최신 4.3 런타임 만 사용할 수 있습니다 (이전 함수를 업데이트해야 함). 이 런타임은 핸들러 함수에 몇 가지 변경 사항을 도입했습니다. 새 핸들러에는 이제 3 개의 매개 변수가 있습니다.

function(event, context, callback)

여전히 succeed, donefail컨텍스트 파라미터를 찾을 수 있지만 AWS는 callback대신 함수 를 사용하도록 제안 하거나 null기본적으로 반환됩니다.

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

전체 설명서는 http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html 에서 찾을 수 있습니다.


4
그렇다면 핸들러 코드를 어떻게 작동 시키나요? 내 이해는 콜백 함수가 호출되도록 context.done ()을 제거해야한다는 것입니다. 하지만 귀하의 코드는 여전히 저에게 작동하지 않습니다. :(
mabeiyi

3
context.done()호출 (성공 및 오류 사건에 대한) 콜백으로 이동해야합니다.
awendt 2015-06-26

2
아직 문제가 없었지만 람다로 나아갈 때 염두에두면 좋습니다.
David

Lambda의 로컬 시스템에서 API를 호출하는 방법에 대한 아이디어가 있습니까?
Amit Kumar Ghosh

2
2017 년 업데이트로 2015 년 질문을 업데이트하기위한 소품!
Ace

19

노드를 이용한 Http 요청의 간단한 작업 예.

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

감사합니다. Lambda가 await 구문을 사용하고 있으므로 2019 년에이 페이지에서 볼 수있는 가장 좋은 답변입니다.
Taneem Tee

3
libs node-fetch request등은 기본적으로 Lambda에서 사용할 수 없기 때문에 최상의 답변을 찾는 데 한 시간 이상이 걸렸습니다 .
Alex C

현재 많은 샘플 코드가 손상된 것 같습니다. 이것은 Node.js 12.x와 함께 AWS Lambda를 사용하는 2020 년 3 월 현재 작동하는 샘플 코드입니다
Muhammad Yussuf

누군가 람다 함수 내부의 데이터로 POST 요청을 만드는 방법을 설명 할 수 있습니까?
Pavindu

11

예, awendt 대답은 완벽합니다. 내 작업 코드를 보여 줄게 ... context.succeed ( 'Blah'); reqPost.end (); 바로 다음 줄 선. 아래에 표시된 곳으로 이동하면 모든 것이 해결되었습니다.

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

Node 10.X 버전에서이 문제에 직면했습니다. 아래는 내 작업 코드입니다.

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

나는 똑같은 문제가 있었고 NodeJS에서의 프로그래밍은 JavaScript를 기반으로 한 Python 또는 Java와 실제로 다르다는 것을 깨달았습니다. 관심이 있거나이 질문에 올 수있는 새로운 사람들이 몇 명있을 수 있으므로 간단한 개념을 사용하려고합니다.

다음 코드를 살펴 보겠습니다.

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 패키지 (1)의 메소드를 호출 할 때마다 이벤트로 생성되며이 이벤트는 별도의 이벤트를 가져옵니다. 'get'함수 (2)는 실제로이 개별 이벤트의 시작점입니다.

이제 (3)의 함수는 별도의 이벤트에서 실행되고 코드는 경로를 계속 실행하고 (4)로 곧바로 점프하여 끝낼 것입니다. 더 이상 할 일이 없기 때문입니다.

그러나 (2)에서 발생한 이벤트는 여전히 어딘가에서 실행 중이며 완료하는 데 자체 시간이 걸립니다. 꽤 기괴하지 않습니까?. 글쎄, 그렇지 않습니다. 이것이 NodeJS가 작동하는 방식이며이 개념에 대해 머리를 감싸는 것이 매우 중요합니다. 이것은 JavaScript Promises가 도움이되는 곳입니다.

여기에서 JavaScript Promise에 대한 자세한 내용을 읽을 수 있습니다. . 요컨대, 코드 실행을 인라인으로 유지하고 새 / 추가 스레드를 생성하지 않으려면 JavaScript Promise가 필요합니다.

대부분의 일반적인 NodeJS 패키지에는 사용 가능한 API의 Promised 버전이 있지만 비슷한 문제를 해결하는 BlueBirdJS와 같은 다른 접근 방식이 있습니다.

위에서 작성한 코드는 다음과 같이 느슨하게 다시 작성할 수 있습니다.

'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로 가져 오는 경우 직접 작동하지 않습니다. Lambda의 경우 코드베이스와 함께 모듈도 패키징해야합니다.


예, 약속합니다! context.done()호출을 체인 finally메서드 로 이동하는 것을 고려할 수 있습니다.
crftr

3

요청을 수행하는 다양한 방법에 대해 웹에서 많은 게시물을 찾았지만 실제로 AWS Lambda에서 응답을 동기식으로 처리하는 방법을 보여주는 게시물은 없습니다.

다음은 https 요청을 사용하고 응답의 전체 본문을 수집 및 반환 processBody하며 결과와 함께 목록에없는 함수에 제어를 전달하는 Node 6.10.3 람다 함수입니다 . 이 코드에서 http와 https는 상호 교환이 가능하다고 생각합니다.

초보자가 이해하기 쉬운 비동기 유틸리티 모듈을 사용하고 있습니다. 이를 사용하려면 AWS 스택에 푸시해야합니다 ( 서버리스 프레임 워크 권장 ).

데이터는 전역 변수에 수집 된 청크로 돌아오고 마지막으로 데이터가 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);
        });
    }
};

0

여기에 이미지 설명 입력

GET-Integration Request> mapping 섹션 아래의 API 게이트웨이에 위 코드를 추가합니다.


-14

예, 실제로 AWS Lambda 유사 및 HTTP 엔드 포인트에 액세스 할 수있는 이유는 많습니다.

AWS Lambda의 아키텍처

마이크로 서비스입니다. Amazon Linux AMI (버전 3.14.26–24.46.amzn1.x86_64)가있는 EC2 내에서 실행되고 Node.js로 실행됩니다. 메모리는 128MB 및 1GB가 될 수 있습니다. 데이터 소스가 이벤트를 트리거하면 세부 정보가 Lambda 함수에 파라미터로 전달됩니다.

무슨 일이야?

AWS Lambda는 컨테이너 내부에서 실행되며 코드는 패키지 또는 모듈과 함께이 컨테이너에 직접 업로드됩니다. 예를 들어, 람다 함수를 실행하는 Linux 머신에 대해 SSH를 수행 할 수 없습니다. 모니터링 할 수있는 유일한 것은 CloudWatchLogs가 포함 된 로그와 런타임에서 발생한 예외입니다.

AWS는 컨테이너 시작 및 종료를 처리하고 코드 만 실행하면됩니다. 따라서 require ( 'http')를 사용하더라도 작동하지 않을 것입니다.이 코드가 실행되는 위치가이를 위해 만들어지지 않았기 때문입니다.


5
내 문제를 오해했을 수도 있습니다. 컨테이너에서 실행되는 Lambda 코드에 대해 알고 있으며 기본 머신에 액세스 할 수 없다는 것도 알고 있습니다. 내가 들어 가려고하는 것도 아니고, 내 코드가 빠져 나 가려고하는데, 즉 외부 엔드 포인트에 액세스하려고하는데 Lambda는 그렇게 할 수 있습니다. 문제는 내 자신의 대답에서 지적했듯이 완전히 다른 것입니다.
awendt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.