Я начинаю работать с 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"
}
Похоже, что часть кода обработчика, которая выполняет запрос, полностью пропускается. Я начал с библиотеки запросов и вернулся к использованию plain, http
чтобы создать минимальный пример. Я также пытался запросить URL-адрес службы, которую я контролирую, для проверки журналов, но никаких запросов не поступает.
Я в полном тупике. Есть ли причина, по которой Node и / или AWS Lambda не выполняет HTTP-запрос?
Ответы:
Конечно, я неправильно понял проблему. Как выразились сами AWS :
Я звонил
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.
источник
context.done()
Вызов должен быть перемещен в функции обратного вызова (для успеха и случае ошибки).Простой рабочий пример 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(); }); }
источник
node-fetch
request
т. Д. По умолчанию недоступны в Lambda.Да, ответ awendt идеален. Я просто покажу свой рабочий код ... У меня был context.succeed ('Мля'); строка сразу после 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 на самом деле отличается от Python или Java, поскольку оно основано на JavaScript. Я постараюсь использовать простые концепции, так как может быть несколько новых людей, которые будут заинтересованы или могут задать этот вопрос.
Посмотрим на следующий код:
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 package (1), он создается как событие, и это событие получает отдельное событие. Функция get (2) фактически является отправной точкой этого отдельного события.
Теперь функция в (3) будет выполняться в отдельном событии, и ваш код продолжит выполнение пути и сразу перейдет к (4) и завершит его, потому что больше нечего делать.
Но событие, запущенное в (2), все еще где-то выполняется, и для завершения потребуется свое приятное время. Довольно странно, правда? Ну нет, это не так. Вот как работает NodeJS, и очень важно, чтобы вы осмыслили эту концепцию. Здесь на помощь приходят обещания JavaScript.
Вы можете узнать больше о обещаниях JavaScript здесь . Вкратце, вам понадобится JavaScript Promise, чтобы поддерживать выполнение кода встроенным и не порождать новые / дополнительные потоки.
Для большинства распространенных пакетов NodeJS доступна обещанная версия API, но есть и другие подходы, такие как 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
метод.Я нашел множество сообщений в Интернете о различных способах выполнения запроса, но ни одна из них не показывала, как синхронно обрабатывать ответ на AWS Lambda.
Вот лямбда-функция Node 6.10.3, которая использует запрос https, собирает и возвращает полное тело ответа и передает управление не включенной в список функции
processBody
с результатами. Я считаю, что http и https в этом коде взаимозаменяемы.Я использую служебный модуль async , который легче понять новичкам. Вам нужно будет отправить это в свой стек AWS, чтобы использовать его (я рекомендую бессерверную структуру ).
Обратите внимание, что данные возвращаются кусками, которые собираются в глобальной переменной, и, наконец, обратный вызов вызывается, когда данные
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); }); } };
источник
Добавьте приведенный выше код в шлюз API в разделе GET-Integration Request> mapping.
источник
Да, на самом деле существует множество причин, по которым вы можете получить доступ к AWS Lambda like и HTTP Endpoint.
Архитектура AWS Lambda
Это микросервис. Работает внутри EC2 с Amazon Linux AMI (версии 3.14.26–24.46.amzn1.x86_64) и работает с Node.js. Память может быть от 128 МБ до 1 ГБ. Когда источник данных запускает событие, подробности передаются в лямбда-функцию как параметры.
Что случилось?
AWS Lambda выполняется внутри контейнера, и код напрямую загружается в этот контейнер с пакетами или модулями. Например, мы НИКОГДА не можем использовать SSH для Linux-машины, на которой выполняется ваша лямбда-функция. Единственное, что мы можем отслеживать, - это журналы с CloudWatchLogs и исключение, пришедшее из среды выполнения.
AWS позаботится о запуске и остановке контейнеров за нас, а просто запустите код. Итак, даже если вы используете require ('http'), это не сработает, потому что место, где запускается этот код, не предназначено для этого.
источник