AWS Lambda无法调用外部https端点

我们正在研究一个Alexa技能,它需要接触到外部REST API来获取数据。 由于某种原因,我很难在lambda函数中使用这个函数。 我也很难确定问题是否在我的node.js代码不正确使用callback,或者如果它在我的函数的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函数。 我没有看到任何错误或成功的消息。 我想也许我没有正确使用callback(节点不是我正常的开发语言),但我实际上是从GitHub上的Amazon示例中直接取出代码,我甚至无法使用它。 (这个代码和它非常相似,除了它稍微短一点。)

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

至于networking的东西,我遵循这个指南: 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中尝试过这个结果。

所以这是解决这个问题: 节点JScallback与Alexa技能

特别是,这条线

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

将https.eet之外的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); } );