109

我开始使用 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"
}

似乎完全跳过了执行请求的处理程序代码部分。我从request lib开始,然后回到使用 plainhttp来创建一个最小的例子。我还尝试请求我控制的服务的 URL 以检查日志并且没有请求进入。

我完全被难住了。Node 和/或 AWS Lambda 是否有任何理由不执行 HTTP 请求?

4

10 回答 10

92

当然,我误解了这个问题。正如 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)

尽管您仍然会在 context 参数上找到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找到

于 2015-02-11T13:42:44.297 回答
47

使用节点的 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();
    });
}
于 2019-06-12T15:48:46.703 回答
13

是的,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();
};
于 2015-09-18T18:07:24.623 回答
8

我在 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();
};
于 2019-11-08T07:15:30.330 回答
6

现代异步/等待示例

您需要防止 lambda 在 https 请求完成之前完成。它也使具有多个请求的代码更易于阅读。

const https = require('https');

// Helper that turns https.request into a promise
function httpsRequest(options) {
    return new Promise((resolve, reject) => {
        const req = https.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);
        });
        
        req.end();
    });
}

// Lambda starts executing here
exports.handler = async event => {
    // --- GET example request  
    var options = {
        method: 'GET',
        hostname: 'postman-echo.com',
        path: encodeURI('/get?foo1=bar1'),
        headers: {
        },
    };

    try {
        const getBody = await httpsRequest(options);
        // The console.log below will not run until the GET request above finishes
        console.log('GET completed successfully! Response body:', getBody);
    } catch (err) {
        console.error('GET request failed, error:', err);
    }

    // --- POST example request  
    var options = {
        method: 'POST',
        hostname: 'postman-echo.com',
        path: encodeURI('/hi/there?hand=wave'),
        headers: {
        },
    };

    try {
        const postBody = await httpsRequest(options);
        // The console.log below will not run until the POST request above finishes
        console.log('POST response body:', postBody);
    } catch (err) {
        console.error('POST request failed, error:', err);
    }
};
于 2021-06-19T02:47:25.683 回答
5

我遇到了同样的问题,然后我意识到 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 包 (1) 中的方法时,它都会被创建为事件,并且此事件会获取它单独的事件。'get' 函数 (2) 实际上是这个单独事件的起点。

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

但是在 (2) 处触发的事件仍在某处执行,它需要自己的甜蜜时间才能完成。很奇怪,对吧?好吧,不,不是。这就是 NodeJS 的工作原理,并且非常重要的是,你要围绕这个概念来思考。这就是 JavaScript Promises 提供帮助的地方。

您可以在此处阅读有关 JavaScript Promises的更多信息。简而言之,您需要一个 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,您还需要将模块与代码库一起打包。

于 2016-05-03T14:02:36.930 回答
5

我在网上找到了很多关于执行请求的各种方法的帖子,但没有一个真正展示如何在 AWS Lambda 上同步处理响应。

这是一个 Node 6.10.3 lambda 函数,它使用 https 请求,收集并返回响应的完整主体,并将控制权传递给processBody带有结果的未列出函数。我相信 http 和 https 在这段代码中是可以互换的。

我正在使用异步实用程序模块,这对于新手来说更容易理解。您需要将其推送到您的 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);
        });
    }
};
于 2018-03-21T04:44:51.233 回答
2

使用带有 resolve reject 的 Promise。它对我有用!

于 2021-06-17T11:55:31.877 回答
-2

在此处输入图像描述

在 GET-Integration Request> 映射部分下的 API 网关中添加上述代码。

于 2020-10-19T11:25:27.410 回答
-16

是的,事实上,您可以访问 AWS Lambda 和 HTTP Endpoint 的原因有很多。

AWS Lambda 的架构

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

发生什么事?

AWS Lambda 在一个容器内运行,代码直接与包或模块一起上传到这个容器。例如,我们永远不能为运行您的 lambda 函数的 linux 机器执行 SSH。我们可以监控的唯一内容是日志、CloudWatchLogs 和来自运行时的异常。

AWS 为我们负责启动和终止容器,然后运行代码。因此,即使您使用 require('http'),它也不会起作用,因为运行此代码的地方不是为此而设计的。

于 2015-02-18T03:42:37.957 回答