【问题标题】:AWS Lambda unable to call external https endpointAWS Lambda 无法调用外部 https 端点
【发布时间】:2017-10-20 02:48:20
【问题描述】:

我们正在开发一项 Alexa 技能,它需要与外部 REST API 联系以获取数据。由于某种原因,我很难让它在我们的 lambda 函数中工作。我也很难确定问题是在我的 node.js 代码中没有正确使用回调,还是在我的函数的 VPC 设置中。这是我的代码,我已经去掉了不必要的东西。

/* eslint-disable  func-names */
/* eslint quote-props: ["error", "consistent"]*/
/**
 * This sample demonstrates a simple skill built with the Amazon Alexa Skills
 * nodejs skill development kit.
 * This sample supports multiple lauguages. (en-US, en-GB, de-DE).
 * The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
 * as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-fact
 **/

'use strict';

const Alexa = require('alexa-sdk');

const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).

const https = require('https');

const handlers = {
    'LaunchRequest': function () {
        this.emit('GetFact');
    },
    'GetNewFactIntent': function () {
        this.emit('GetFact');
    },
    'maintenanceIntent': function () {
        console.log('inside maintenanceIntent');

    var options = {
        host: 'api.forismatic.com',
        path: '/api/1.0/?method=getQuote&lang=en&format=text',
        method: 'GET'
    };

    getQuote(options, function (quote){
            if(quote === ''){
                console.log("No quote");
                //speechOutput = "Please try again later";
            }
            else{console.log(quote)}
            //self.emit(':tellWithCard', speechOutput, SKILL_NAME, text);
        });

        // Create speech output
        // Place holder
        var randomFact = 'Test Fact';
        const speechOutput = randomFact;
        this.emit(':tellWithCard', speechOutput, 'test skill name', randomFact);
    },
    'AMAZON.HelpIntent': function () {
        const speechOutput = this.t('HELP_MESSAGE');
        const reprompt = this.t('HELP_MESSAGE');
        this.emit(':ask', speechOutput, reprompt);
    },
    'AMAZON.CancelIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
    'AMAZON.StopIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
};

exports.handler = function (event, context, callback) {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    //alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

function getQuote(options, callback){
    var text = '';
    console.log("in getquote");
    https.get(options, function(res) {
        console.error("Got response: " + res.statusCode);
        res.on("data", function(chunk) {
        console.error("BODY: " + chunk);
        text = '' + chunk;
        return callback(text);
    });
    }).on('error', function(e) {
        text = 'error' + e.message;
        console.error("Got error: " + e.message);
});
}

现在,当我调用 maintenanceIntent 时,这就是我在日志中看到的内容。

{"timestamp":1508426249817,"message":"START RequestId: 9f66123e-b4e0-11e7-baac-1bfb01d2abc8 Version: $LATEST","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
{"timestamp":1508426250256,"message":"Warning: Application ID is not set","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
{"timestamp":1508426250256,"message":"inside maintenanceIntent","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
{"timestamp":1508426250256,"message":"in getquote","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
{"timestamp":1508426250256,"message":"END RequestId: 9f66123e-b4e0-11e7-baac-1bfb01d2abc8","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
{"timestamp":1508426250256,"message":"REPORT RequestId: 9f66123e-b4e0-11e7-baac-1bfb01d2abc8\tDuration: 378.28 ms\tBilled Duration: 400 ms \tMemory Size: 128 MB\tMax Memory Used: 33 MB\t","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}

所以我可以看到它实际上是在调用 getQuote 函数。我根本没有看到任何错误或成功消息。我想也许我没有正确使用回调(节点不是我的正常开发语言),但我实际上是直接从 GitHub 上的亚马逊示例中提取代码,我什至无法让它工作。 (此代码与它非常相似,只是它更短一些。)

如果我剥离它并通过节点在本地运行它,它工作正常。

至于网络的东西,我遵循了这个指南:https://gist.github.com/reggi/dc5f2620b7b4f515e68e46255ac042a7 .我也尝试过亚马逊指南,但目前我什至不确定如何检查互联网连接,或者这是否是问题所在。

我们将不胜感激任何有助于走上正轨的帮助!

--编辑--

我已经更改了我的代码。这直接来自https://raw.githubusercontent.com/alexa/alexa-cookbook/master/external-calls/httpsGet/src/index.js的alexa-cookbook

/* eslint-disable  func-names */
/* eslint quote-props: ["error", "consistent"]*/
/**
 * This sample demonstrates a simple skill built with the Amazon Alexa Skills
 * nodejs skill development kit.
 * This sample supports multiple lauguages. (en-US, en-GB, de-DE).
 * The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
 * as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-fact
 **/

'use strict';

const Alexa = require('alexa-sdk');

const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).

const https = require('https');

const handlers = {
    'LaunchRequest': function () {
        this.emit('GetFact');
    },
    'GetNewFactIntent': function () {
        this.emit('GetFact');
    },
    'maintenanceIntent': function () {
        console.log('inside maintenanceIntent');

    var myRequest = 'Florida';

    httpsGet(myRequest,  (myResult) => {
                console.log("sent     : " + myRequest);
                console.log("received : " + myResult);

                this.response.speak('The population of ' + myRequest + ' is ' + myResult);
                this.emit(':responseReady');

            }
        );

        // Create speech output
        // Place holder
        var randomFact = 'Test Fact';
        const speechOutput = randomFact;
        this.emit(':tellWithCard', speechOutput, 'test skill name', randomFact);
    },
    'AMAZON.HelpIntent': function () {
        const speechOutput = this.t('HELP_MESSAGE');
        const reprompt = this.t('HELP_MESSAGE');
        this.emit(':ask', speechOutput, reprompt);
    },
    'AMAZON.CancelIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
    'AMAZON.StopIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
};

exports.handler = function (event, context, callback) {
    console.log("exports handler");
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    //alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
    console.log("post execute");
};

function httpsGet(myData, callback) {

    // GET is a web service request that is fully defined by a URL string
    // Try GET in your browser:
    // https://cp6gckjt97.execute-api.us-east-1.amazonaws.com/prod/stateresource?usstate=New%20Jersey

    console.log("in");
    console.log(myData);
    // Update these options with the details of the web service you would like to call
    var options = {
        host: 'cp6gckjt97.execute-api.us-east-1.amazonaws.com',
        port: 443,
        path: '/prod/stateresource?usstate=' + encodeURIComponent(myData),
        method: 'GET',

        // if x509 certs are required:
        // key: fs.readFileSync('certs/my-key.pem'),
        // cert: fs.readFileSync('certs/my-cert.pem')
    };

    var req = https.request(options, res => {
        res.setEncoding('utf8');
        var returnData = "";
        console.log("request");
        res.on('data', chunk => {
            console.log("data");
            returnData = returnData + chunk;
        });

        res.on('end', () => {
            console.log("end");
            // we have now received the raw return data in the returnData variable.
            // We can see it in the log output via:
            // console.log(JSON.stringify(returnData))
            // we may need to parse through it to extract the needed data

            var pop = JSON.parse(returnData).population;

            callback(pop);  // this will execute whatever function the caller defined, with one argument

        });

    });
    console.log("req.end");
    req.end();

}

从端点获取结果的想法相同,但执行方式略有不同。这是日志输出。

{"timestamp":1508434982754,"message":"START RequestId: f4a39351-b4f4-11e7-a563-fbf7599fa72f Version: $LATEST","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434982887,"message":"exports handler","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434982887,"message":"Warning: Application ID is not set","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434982887,"message":"inside maintenanceIntent","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434982887,"message":"in","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434982887,"message":"Florida","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434983307,"message":"req.end","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434983309,"message":"post execute","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434983367,"message":"END RequestId: f4a39351-b4f4-11e7-a563-fbf7599fa72f","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
{"timestamp":1508434983367,"message":"REPORT RequestId: f4a39351-b4f4-11e7-a563-fbf7599fa72f\tDuration: 608.20 ms\tBilled Duration: 700 ms \tMemory Size: 128 MB\tMax Memory Used: 35 MB\t","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}

我在 VPC 和 VPC 外都试过这个,结果相同。

【问题讨论】:

  • 您的子网/NAT 设置中可能配置错误。要验证您的函数是否可以调用 api.forismatic.com,请将 lambda 从 vpc 中取出。完成后,您可以重新访问网络设置
  • 你也没有调用处理程序中提供的callback函数
  • 如果您的 Lambda 函数位于 VPC 中,它将无法访问 VPC 之外的任何资源。如果您希望 Lambda 函数能够访问 VPC 资源和外部资源,则必须将 Lambda 函数放置在您的 VPC 的私有子网中,该子网具有到 NAT 网关的路由。我没有看到您实际上在您的 Lambda 函数中执行任何需要 VPC 访问的操作。如果您真的不需要 VPC 访问权限,最快的解决方法是从 VPC 中删除您的函数。
  • @Unglückspilz 我已经用 VPC 中的 lambda 进行了尝试,结果相同。我用新信息编辑了帖子。另外,不确定您的意思是它没有在处理程序中调用回调函数。我对节点不太熟悉,但我看到的所有示例似乎都与我尝试使用的代码相匹配。
  • @MarkB 我在没有 VPC 的情况下尝试过,结果相同。

标签: node.js amazon-web-services aws-lambda


【解决方案1】:

这个问题解决了:Node JS callbacks with Alexa skill

尤其是这一行

:tell 函数将调用 lambda 回调并终止 lambda 函数的执行。

将 this.emit 移到 httpsGet 之外,就像这样解决了问题。

httpsGet(myRequest,  (myResult) => {
                console.log("sent     : " + myRequest);
                console.log("received : " + myResult);

                this.response.speak('The population of ' + myRequest + ' is ' + myResult);
                this.emit(':responseReady');

                // Create speech output
                // Place holder
                var randomFact = 'Test Fact';
                const speechOutput = randomFact;
                this.emit(':tellWithCard', speechOutput, 'test skill name', randomFact);
            }
        );

【讨论】:

    猜你喜欢
    • 2020-11-21
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 2021-11-16
    • 2022-10-23
    • 2016-06-03
    • 2018-07-01
    • 1970-01-01
    相关资源
    最近更新 更多