为什么这个HTTP请求在AWS Lambda上不起作用?

我开始使用AWS Lambda,并试图从我的处理函数请求一个外部服务。 根据这个答案 ,HTTP请求应该工作得很好,我还没有发现任何其他文件。 (事实上​​,人们已经发布了使用Twilio API发送短信的代码 。)

我的处理程序代码是:

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 

但是这是缺less的。 如果我在本地机器上使用节点中没有处理程序包装的重要部分,则代码将按预期工作。

我使用的inputfile.txtinvoke-async调用是这样的:

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

这似乎是处理程序代码的一部分,请求被完全跳过。 我开始与请求库,并回落到使用普通的http创build一个最小的例子。 我也试图请求一个我控制的服务的URL来检查日志,并没有请求进来。

我完全难住。 节点和/或AWS Lambda是否有任何原因不会执行HTTP请求?

当然,我误解了这个问题。 正如AWS自己所说 :

对于那些在Lambda中第一次遇到nodejs的人来说,一个常见的错误就是忘记了这个callback是asynchronous执行的,并且当你真的打算等待另一个callback(比如S3.PUT操作)时,在原始处理程序中调用context.done()完成,迫使function终止,其工作不完整。

在请求的任何callback被触发之前,我调用了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运行时(旧function应该更新)。 这个运行时引入了对处理函数的一些修改。 新的处理程序现在有3个参数。

 function(event, context, callback) 

尽pipe您仍然会发现上下文参数succeeddonefail ,但AWSbuild议使用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.htmlfind。;

是的,答案是完美的。 我只会显示我的工作代码…我有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(); }; 

我有同样的问题,然后我意识到在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 package(1)中的一个方法时,它将被创build为事件,并且这个事件会获得单独的事件。 “get”函数(2)实际上是这个单独事件的起点。

现在,(3)中的函数将在一个单独的事件中执行,并且您的代码将继续执行path,并将直接跳转到(4)并完成它,因为没有更多的事情要做。

但(2)发起的事件仍然在执行某个地方,它将花费自己的甜蜜时间来完成。 很奇怪,对不对? 那么,不,不是。 这就是NodeJS的工作原理,它很重要,可以围绕这个概念进行考虑。 这是JavaScript的承诺来帮助的地方。

你可以在这里阅读更多关于JavaScript的承诺。 简而言之,您需要一个JavaScript Promise来保持内联代码的执行,并且不会产生新的/额外的线程。

大部分常见的NodeJS包都提供了可用API的Promise版本,但是还有其他一些方法,如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和HTTP端点一样。

AWS Lambda的体系结构

这是一个微服务。 使用Amazon Linux AMI(版本3.14.26-24.46.amzn1.x86_64)在EC2内部运行,并使用Node.js运行。 内存可以是128MB和1GB。 数据源触发事件时,详细信息将作为parameter passing给Lambda函数。

发生什么事?

AWS Lambda运行在一个容器中,代码直接上传到包装或模块的容器中。 例如,我们永远不能为运行你的lambda函数的linux机器执行SSH。 我们可以监控的唯一事情是日志,CloudWatchLogs和来自运行时的exception。

AWS负责启动并终止我们的容器,并运行代码。 所以,即使你使用require('http'),它也不会工作,因为这个代码运行的地方并不是为了这个。