【问题标题】:How to make an external api call within an AWS Lambda function如何在 AWS Lambda 函数中进行外部 api 调用
【发布时间】:2020-04-17 21:43:38
【问题描述】:

我遇到了问题Lambda函数由于某种原因它超时

我尝试添加一些 console.log 来了解发生了什么,在外部 http 请求之前一切正常

我使用 npm 模块请求

我可以在请求之前看到日志,但回调中的日志从不显示,就像端点没有响应一样。

我错过了什么吗?提前致谢!

var mysql = require('mysql'); 
var request = require('request');
var config = require('./config.json'); 

var pool = mysql.createPool({
  host: config.dbhost,
  user: config.dbuser,
  password: config.dbpassword,
  database: config.dbname
});

var openWeatherOptions = (device) => {
    let domain = 'https://api.openweathermap.org/data/2.5/';
    let apiEndpoint = 'weather?';
    let params = `lat=${device.lat}&lon=${device.lng}&APPID=${process.env.WEATHER_APP_ID}&units=metric`;
    let url = [domain, apiEndpoint, params].join('').toString();
    return {
      url: url,
      method: 'GET',
      headers: { 'Content-Type': 'application/json'},
    };
};

exports.handler = (event, context, callback) => {
    context.callbackWaitsForEmptyEventLoop = false;
    // Connect to DB
    console.log('fallback connecting to DB')
    pool.getConnection( (errOnConnection, connection) => {
        if(errOnConnection) {
            callback({"err": errOnConnection });
        }
        console.log('fallback connected to DB')
        // Retrieve device position
        let queryOne = 'SELECT lat, lng FROM T03_DevicesPosition WHERE deviceCode = (?);';
        console.log('fallback retrieving device position')
        connection.query( queryOne, [event.device], (errOnQ1, results, fields) => { 
            if(errOnQ1) {
                connection.release();
                callback({"err": errOnQ1 });
            }
            console.log('fallback device position retrieved')

            // Call openweather 
            let device = results[0];
            let options = openWeatherOptions(device);
            console.log('fallback calling openWeather with following data: ', device, options);

            request( options, (errOpenWeather, response, body) => {
                console.log('fallback openweather response received');
                if(errOpenWeather || (response.statusCode !== 200 && response.statusCode !== 201) ) {
                    connection.release();
                    callback({"err": errOpenWeather });
                }
                let meteo = JSON.parse(body).main;
                meteo.date = new Date(event.time*1000);
                meteo.pressure = Math.floor( meteo.pressure );
                console.log('fallback storing data', meteo);
                let query = `INSERT INTO T02_DevicesTransmissions (deviceCode, transmissionDate, temperature, humidity, pressure, unixDate, rawData) VALUES ( ?, ?, ?, ?, ?, ?, ?);`;
                let queryValues = [ event.device, meteo.date, meteo.temp, meteo.humidity, meteo.pressure, event.time, 'fallback']; 
                connection.query( query, queryValues, (errInsert, results, fields) => { 
                    connection.release();
                    console.log('fallback completed with', errInsert ? '' : 'out');
                    if (errInsert) callback({"err": errInsert });
                    else callback();
                });
            });

        });
    });
}

【问题讨论】:

标签: node.js aws-lambda npm-request


【解决方案1】:

这是一个老问题,但我花了几个小时思考如何正确设置它,所以希望能节省其他人的时间:)

如果您的 lambda 在 VPC 中,它们需要通过 NAT 网关才能访问外部服务。

实现此目的的一种方法是:

  • 配置您的 lambda 以使用一个(或多个)特定子网(Lambda 控制台会建议您将不同可用区中的至少 2 个子网与您的 lambda 关联以确保可用性)
  • 不同的子网中创建一个 NAT 网关
  • 让与您的 lambda 子网关联的路由表将所有出站流量 (0.0.0.0/0) 发送到您创建的 NAT 网关(您可以通过在 target 字段中选择 NAT 来实现)
  • 让 NAT 子网中的路由表将所有出站流量发送到 Internet 网关

这将通过 NAT 和 Internet 网关正确路由来自您的 lambda 的流量,以便它们可以访问外部服务。

请注意,如果您还使用 lambda 中的 RDS,并且您还打算从外部连接到 RDS(例如,从本地计算机管理数据库),则不能将 RDS 实例放入 lambda 的子网中,否则您将无法从外部连接到它(NAT 仅出站)。在这种情况下,您应该确保您的 RDS 实例与可访问的子网相关联,例如 NAT 所在的子网(即向 Internet 网关发送出站流量的子网)。

【讨论】:

  • 是的,这是正确的答案,我不记得我是如何理解它的,但我不会忘记阅读一页又一页的文档的挣扎。另外,我记得为 lambda 配置提供一个或多个子网很重要(不记得它们是否需要私有、公共或没有不同)
  • 是的,AWS 网络需要一些时间来适应...您确实需要将子网关联到其 VPC 配置中的 lambda(AWS 建议在不同的可用区中至少有 2 个,并且每次实例化 lambda 时它都会选择一个)。重要的部分是这些子网的路由表需要将出站流量发送到 NAT(它本身需要有互联网访问权限)。
  • 非常感谢我已经花费了 6 个多小时的时间在谷歌上搜索并尝试了 nodejs http 请求的每个代码变体,我在扯头发时可以想到。这有效并救了我。感谢您的记录。
  • NAT 网关费用约为 30 美元/月。如果您可以从外部服务建立 vpc 对等连接,它将是免费的。不过,两者都使用数据传输定价。大约 0.04/gb 的 nat 和 0.01 的对等连接,至少今天在 n.virginia 地区
  • @LukasLiesis 你会链接我可以阅读的任何资源吗?
【解决方案2】:

您没有 VPC 集,对吗?如果这样做,如果您在私有子网上,则必须检查您是否连接了 NAT 网关。

【讨论】:

【解决方案3】:

这是您的解决方案,请阅读。

https://forums.developer.amazon.com/questions/95692/invoking-a-rest-api-from-within-a-lambda-function.html

进一步

此代码示例展示了如何在您的技能 Lambda 代码中调用和接收外部休息服务数据。 https://github.com/robm26/SkillsDataAccess/blob/master/src/CallService/index.js

【讨论】:

    猜你喜欢
    • 2020-11-21
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    • 2021-05-24
    • 2018-08-28
    • 2018-08-13
    相关资源
    最近更新 更多