2015-02-11 117 views
48

我开始使用AWS Lambda,并试图从我的处理函数请求外部服务。根据this answer,HTTP请求应该可以正常工作,而且我还没有发现任何其他文档。 (事实上​​,人们已经发布code that use the Twilio API to send SMS为什么此HTTP请求无法在AWS Lambda上运行?

我的处理程序代码是:

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

好像处理程序代码,不会请求被完全忽略的一部分。我从request lib开始,并回到使用普通http创建一个最小的例子。我也试图请求我控制的服务的URL来检查日志,并且没有请求进来。

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

+0

我认为这可能是由于HTTP请求中缺少用户代理引起的。 – 2015-02-11 10:55:52

+3

在撰写本文时,这是目前AWS论坛Lambda论坛中的首要问题。这让我疯狂,也是一群其他人。 – Nostradamus 2015-06-28 22:13:09

+0

@Nostradamus我很欣赏任何其他反馈,更正和upvotes。把它们发送到这里;-) – awendt 2015-06-29 07:37:41

回答

52

当然,我误解了这个问题。 As AWS themselves put it

对于在拉姆达的那些第一次遇到的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已弃用旧0.10的NodeJS,只有较新的4.3运行时现已(旧功能应更新)。该运行时引入了对处理函数的一些更改。新的处理程序现在有3个参数。

function(event, context, callback) 

虽然你仍然会发现上下文参数succeeddonefail,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 2015-06-25 04:50:07

+3

'context.done()'调用需要移入回调(成功和错误的情况下) – awendt 2015-06-26 12:37:26

+2

还没有你的问题,但要记住,因为我向前迈进lambda – 2015-07-22 13:11:14

-9

是的,有其实也可以找到很多原因,你可以访问AWS LAMBDA喜欢和HTTP端点。

AWS的体系结构Lambda

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

会发生什么?

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

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

+5

您可能误解了我的问题我了解有关运行在容器中的Lambda代码,并且我知道我不能访问底层机器,我也不想进入,我的代码试图跳出,即访问外部端点,而Lambda可以很好地完成这个问题。在我自己的回答中已经指出了 – awendt 2015-02-18 09:38:40

+1

这里与你的建筑没有关系...... – 2016-12-03 12:10:18

10

是的,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(); 
}; 
3

我有同样的问题,然后我意识到,作为其基于JavaScript编程是的NodeJS比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承诺here。简而言之,您需要一个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,您还需要将模块与代码库打包在一起。

+0

是的,承诺!虽然我会考虑移动'context.done()'调用链接的'finally'方法。 – crftr 2016-06-04 20:02:42

相关问题