Node.js AWS Lambda无法调用外部https端点
我们正在研究Alexa技能,它需要接触外部RESTAPI来获取数据。出于某种原因,我很难在lambda函数中使用它。我也很难确定问题是在我的node.js代码中没有正确使用回调函数,还是在我的函数的VPC设置中。这是我的代码,我去掉了不必要的东西Node.js AWS Lambda无法调用外部https端点,node.js,amazon-web-services,aws-lambda,Node.js,Amazon Web Services,Aws Lambda,我们正在研究Alexa技能,它需要接触外部RESTAPI来获取数据。出于某种原因,我很难在lambda函数中使用它。我也很难确定问题是在我的node.js代码中没有正确使用回调函数,还是在我的函数的VPC设置中。这是我的代码,我去掉了不必要的东西 /* eslint-disable func-names */ /* eslint quote-props: ["error", "consistent"]*/ /** * This sample demonstrates a simple ski
/* 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);
});
}
现在,当我调用MaintenanceContent时,这就是我在日志中看到的内容
{"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函数。我没有看到任何错误或成功消息。我想也许我没有正确地使用回调(node不是我的正常开发语言),但实际上我直接从GitHub上的一个Amazon示例中提取了代码,我甚至无法实现这一点。(此代码与之非常相似,只是略短一些。)
如果我将其剥离并通过节点在本地运行,它就可以正常工作
至于网络方面,我遵循以下指南:
. 我也尝试过Amazon指南,但在这一点上,我甚至不确定如何检查互联网连接,或者这是否是问题所在
如果您能帮助我们走上正轨,我们将不胜感激
--编辑--
我把代码也改了。这是直接从alexa在
相同的想法,但从端点获取结果的执行略有不同。这是日志输出
{"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内外都尝试过这个方法,结果是一样的。所以这个问题解决了,这要归功于这个问题: 尤其是这一行 :tell函数将调用lambda回调并终止lambda函数的执行 将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);
}
);
您的子网/NAT设置中可能存在错误配置。要验证您的函数是否可以调用
api.forismatic.com
,请将lambda从vpc中取出。完成后,您可以重新访问网络设置。您也不会调用Handler中提供的回调
函数。如果Lambda函数位于专有网络中,则它将无法访问专有网络之外的任何资源。如果希望Lambda功能能够访问专有网络资源和外部资源,则必须将Lambda功能放置在专有网络的私有子网中,该子网具有到NAT网关的路由。我看不到您在Lambda函数中实际执行任何需要VPC访问的操作。如果你真的不需要VPC访问,最快的修复方法就是从你的VPC中删除你的功能。@Unglückspilz我已经用lambda从VPC中删除了它,结果是一样的。我用新信息编辑了这篇文章。另外,不确定您的意思是什么,它没有调用处理程序中的回调函数。我对node不太熟悉,但我看到的所有示例似乎都与我尝试使用的代码相匹配。@MarkB我在没有VPC的情况下尝试了它,得到了相同的结果。
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);
}
);