【发布时间】: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