[node.js] 이 HTTP 요청이 AWS Lambda에서 작동하지 않는 이유는 무엇입니까?
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 요청을 실행하지 않는 이유가 있습니까?
답변
물론 나는 문제를 오해하고 있었다. 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
, done
및 fail
컨텍스트 파라미터를 찾을 수 있지만 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 에서 찾을 수 있습니다.
답변
노드를 이용한 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();
});
}
답변
예, 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();
};
답변
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();
};
답변
나는 똑같은 문제가 있었고 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의 경우 코드베이스와 함께 모듈도 패키징해야합니다.
답변
요청을 수행하는 다양한 방법에 대해 웹에서 많은 게시물을 찾았지만 실제로 AWS Lambda에서 응답을 동기식으로 처리하는 방법을 보여주는 게시물은 없습니다.
다음은 https 요청을 사용하고 응답의 전체 본문을 수집 및 반환 processBody
하며 결과와 함께 목록에없는 함수에 제어를 전달하는 Node 6.10.3 람다 함수입니다 . 이 코드에서 http와 https는 상호 교환이 가능하다고 생각합니다.
초보자가 이해하기 쉬운 비동기 유틸리티 모듈을 사용하고 있습니다. 이를 사용하려면 AWS 스택에 푸시해야합니다 ( 서버리스 프레임 워크 권장 ).
데이터는 전역 변수에 수집 된 청크로 돌아오고 마지막으로 데이터가 end
ed 일 때 콜백이 호출됩니다 .
'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);
});
}
};