简体   繁体   English

AWS Lambda 无法调用外部 https 端点

[英]AWS Lambda unable to call external https endpoint

We are working on an Alexa skill and it will need to reach out to external REST API's to get data.我们正在研究 Alexa 技能,它需要联系外部 REST API 以获取数据。 I'm having a really hard time getting this to work in our lambda function for some reason.由于某种原因,我很难让它在我们的 lambda 函数中工作。 I'm also having a hard time determining if the problem is in my node.js code not using callback's correctly or if it's in the VPC settings for my function.我也很难确定问题是在我的 node.js 代码中没有正确使用回调,还是在我的函数的 VPC 设置中。 Here is my code, I've stripped out the non-essential stuff.这是我的代码,我去掉了非必要的东西。

/* 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);
});
}

Now when I invoke the maintenanceIntent this is what I see in the logs.现在,当我调用 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"}

So I can see it's actually calling the getQuote function.所以我可以看到它实际上是在调用 getQuote 函数。 I'm not seeing any errors or success messages at all.我根本没有看到任何错误或成功消息。 I thought maybe I wasn't using callbacks correctly (node isn't my normal development language) but I've actually pulled code straight from an Amazon example on GitHub and I couldn't even get that to work.我想也许我没有正确使用回调(节点不是我的正常开发语言),但我实际上直接从 GitHub 上的亚马逊示例中提取了代码,我什至无法让它工作。 (This code is very similar to it except it's a little shorter.) (这段代码与它非常相似,只是它有点短。)

If I strip this down and run it locally through the node, it works fine.如果我剥离它并通过节点在本地运行它,它工作正常。

As far as the networking stuff, I followed this guide: https://gist.github.com/reggi/dc5f2620b7b4f515e68e46255ac042a7 .至于网络方面的东西,我遵循了这个指南: https : //gist.github.com/reggi/dc5f2620b7b4f515e68e46255ac042a7 I've also tried Amazon guides but at this point, I'm not even sure how I would check internet connectivity or if this is even the problem.我也试过亚马逊指南,但在这一点上,我什至不确定我将如何检查互联网连接,或者这是否是问题所在。

Any help to get on the right track would be greatly appreciated!任何帮助走上正轨将不胜感激!

--EDIT-- - 编辑 -

I've changed my code as so.我已经改变了我的代码。 This comes straight from the alexa-cookbook at https://raw.githubusercontent.com/alexa/alexa-cookbook/master/external-calls/httpsGet/src/index.js这直接来自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();

}

Same idea but slightly different execution of getting the result from the endpoint.相同的想法,但从端点获取结果的执行略有不同。 This is the log output.这是日志输出。

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

I've tried this in the VPC and out of the VPC with the same result.我在 VPC 和 VPC 外都尝试过,结果相同。

So this is solved thanks to this question: Node JS callbacks with Alexa skill所以这要归功于这个问题解决了: Node JS callbacks with Alexa Skill

Particurlarly, this line尤其是这条线

The :tell function will call the lambda callback and terminate the execution of the lambda function. :tell 函数将调用 lambda 回调并终止 lambda 函数的执行。

Moving the this.emit outside the httpsGet into it like so fixed the issue.将 httpsGet 之外的 this.emit 移入其中,就像这样解决了问题。

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);
            }
        );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM