如何使用 Lambda 函数对 Alexa Skill 应用程序进行异步 api 调用?
How to make an asynchronous api call for Alexa Skill application with a Lambda function?
我想从 Lambda 函数调用 api。我的处理程序由包含两个必需插槽的意图触发。因此,我事先不知道我是 returning Dialog.Delegate
指令还是 api 请求的响应。我如何在调用意图处理程序时承诺这些 return 值?
这是我的经纪人:
const FlightDelayIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'MyIntent';
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
if (request.dialogState != "COMPLETED"){
return handlerInput.responseBuilder
.addDelegateDirective(request.intent)
.getResponse();
} else {
// Make asynchronous api call, wait for the response and return.
var query = 'someTestStringFromASlot';
httpGet(query, (result) => {
return handlerInput.responseBuilder
.speak('I found something' + result)
.reprompt('test')
.withSimpleCard('Hello World', 'test')
.getResponse();
});
}
},
};
这是我发出请求的辅助函数:
const https = require('https');
function httpGet(query, callback) {
var options = {
host: 'myHost',
path: 'someTestPath/' + query,
method: 'GET',
headers: {
'theId': 'myId'
}
};
var req = https.request(options, res => {
res.setEncoding('utf8');
var responseString = "";
//accept incoming data asynchronously
res.on('data', chunk => {
responseString = responseString + chunk;
});
//return the data when streaming is complete
res.on('end', () => {
console.log('==> Answering: ');
callback(responseString);
});
});
req.end();
}
所以我怀疑我将不得不使用 promises 并在我的句柄函数前面放一个 "async" ?我对所有这一切都很陌生,所以我不知道这意味着什么,特别是考虑到我有两个不同的 return 值,一个是直接的,另一个是延迟的。我该如何解决?
提前致谢。
正如您所怀疑的,您的处理程序代码在异步调用 http.request 之前完成,因此 Alexa SDK 没有从 handle
函数接收到任何 return 值并将 return 对 Alexa 的无效响应。
我将您的代码稍微修改为 运行 它在笔记本电脑本地以说明问题:
const https = require('https');
function httpGet(query, callback) {
var options = {
host: 'httpbin.org',
path: 'anything/' + query,
method: 'GET',
headers: {
'theId': 'myId'
}
};
var req = https.request(options, res => {
res.setEncoding('utf8');
var responseString = "";
//accept incoming data asynchronously
res.on('data', chunk => {
responseString = responseString + chunk;
});
//return the data when streaming is complete
res.on('end', () => {
console.log('==> Answering: ');
callback(responseString);
});
});
req.end();
}
function FlightDelayIntentHandler() {
// canHandle(handlerInput) {
// return handlerInput.requestEnvelope.request.type === 'IntentRequest'
// && handlerInput.requestEnvelope.request.intent.name === 'MyIntent';
// },
// handle(handlerInput) {
// const request = handlerInput.requestEnvelope.request;
// if (request.dialogState != "COMPLETED"){
// return handlerInput.responseBuilder
// .addDelegateDirective(request.intent)
// .getResponse();
// } else {
// Make asynchronous api call, wait for the response and return.
var query = 'someTestStringFromASlot';
httpGet(query, (result) => {
console.log("I found something " + result);
// return handlerInput.responseBuilder
// .speak('I found something' + result)
// .reprompt('test')
// .withSimpleCard('Hello World', 'test')
// .getResponse();
});
console.log("end of function reached before httpGet will return");
// }
// }
}
FlightDelayIntentHandler();
到运行这段代码,别忘了npm install http
,然后是node test.js
。它产生
stormacq:~/Desktop/temp $ node test.js
end of function reached before httpGet will return
==> Answering:
I found something {
"args": {},
"data": "",
...
因此,关键是要等待 http get
到 return,然后再 return 对 Alexa 的响应。为此,我建议将您的 httpGet
函数修改为 return 承诺,而不是使用回调。
修改后的代码是这样的(我保留了你原来的代码作为注释)
const https = require('https');
async function httpGet(query) {
return new Promise( (resolve, reject) => {
var options = {
host: 'httpbin.org',
path: 'anything/' + query,
method: 'GET',
headers: {
'theId': 'myId'
}
};
var req = https.request(options, res => {
res.setEncoding('utf8');
var responseString = "";
//accept incoming data asynchronously
res.on('data', chunk => {
responseString = responseString + chunk;
});
//return the data when streaming is complete
res.on('end', () => {
console.log('==> Answering: ');
resolve(responseString);
});
//should handle errors as well and call reject()!
});
req.end();
});
}
async function FlightDelayIntentHandler() {
// canHandle(handlerInput) {
// return handlerInput.requestEnvelope.request.type === 'IntentRequest'
// && handlerInput.requestEnvelope.request.intent.name === 'MyIntent';
// },
// handle(handlerInput) {
// const request = handlerInput.requestEnvelope.request;
// if (request.dialogState != "COMPLETED"){
// return handlerInput.responseBuilder
// .addDelegateDirective(request.intent)
// .getResponse();
// } else {
// Make asynchronous api call, wait for the response and return.
var query = 'someTestStringFromASlot';
var result = await httpGet(query);
console.log("I found something " + result);
// return handlerInput.responseBuilder
// .speak('I found something' + result)
// .reprompt('test')
// .withSimpleCard('Hello World', 'test')
// .getResponse();
//});
console.log("end of function reached AFTER httpGet will return");
// }
// }
}
FlightDelayIntentHandler();
运行 此代码生成:
stormacq:~/Desktop/temp $ node test.js
==> Answering:
I found something{
"args": {},
"data": "",
...
end of function reached AFTER httpGet will return
我想从 Lambda 函数调用 api。我的处理程序由包含两个必需插槽的意图触发。因此,我事先不知道我是 returning Dialog.Delegate
指令还是 api 请求的响应。我如何在调用意图处理程序时承诺这些 return 值?
这是我的经纪人:
const FlightDelayIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'MyIntent';
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
if (request.dialogState != "COMPLETED"){
return handlerInput.responseBuilder
.addDelegateDirective(request.intent)
.getResponse();
} else {
// Make asynchronous api call, wait for the response and return.
var query = 'someTestStringFromASlot';
httpGet(query, (result) => {
return handlerInput.responseBuilder
.speak('I found something' + result)
.reprompt('test')
.withSimpleCard('Hello World', 'test')
.getResponse();
});
}
},
};
这是我发出请求的辅助函数:
const https = require('https');
function httpGet(query, callback) {
var options = {
host: 'myHost',
path: 'someTestPath/' + query,
method: 'GET',
headers: {
'theId': 'myId'
}
};
var req = https.request(options, res => {
res.setEncoding('utf8');
var responseString = "";
//accept incoming data asynchronously
res.on('data', chunk => {
responseString = responseString + chunk;
});
//return the data when streaming is complete
res.on('end', () => {
console.log('==> Answering: ');
callback(responseString);
});
});
req.end();
}
所以我怀疑我将不得不使用 promises 并在我的句柄函数前面放一个 "async" ?我对所有这一切都很陌生,所以我不知道这意味着什么,特别是考虑到我有两个不同的 return 值,一个是直接的,另一个是延迟的。我该如何解决?
提前致谢。
正如您所怀疑的,您的处理程序代码在异步调用 http.request 之前完成,因此 Alexa SDK 没有从 handle
函数接收到任何 return 值并将 return 对 Alexa 的无效响应。
我将您的代码稍微修改为 运行 它在笔记本电脑本地以说明问题:
const https = require('https');
function httpGet(query, callback) {
var options = {
host: 'httpbin.org',
path: 'anything/' + query,
method: 'GET',
headers: {
'theId': 'myId'
}
};
var req = https.request(options, res => {
res.setEncoding('utf8');
var responseString = "";
//accept incoming data asynchronously
res.on('data', chunk => {
responseString = responseString + chunk;
});
//return the data when streaming is complete
res.on('end', () => {
console.log('==> Answering: ');
callback(responseString);
});
});
req.end();
}
function FlightDelayIntentHandler() {
// canHandle(handlerInput) {
// return handlerInput.requestEnvelope.request.type === 'IntentRequest'
// && handlerInput.requestEnvelope.request.intent.name === 'MyIntent';
// },
// handle(handlerInput) {
// const request = handlerInput.requestEnvelope.request;
// if (request.dialogState != "COMPLETED"){
// return handlerInput.responseBuilder
// .addDelegateDirective(request.intent)
// .getResponse();
// } else {
// Make asynchronous api call, wait for the response and return.
var query = 'someTestStringFromASlot';
httpGet(query, (result) => {
console.log("I found something " + result);
// return handlerInput.responseBuilder
// .speak('I found something' + result)
// .reprompt('test')
// .withSimpleCard('Hello World', 'test')
// .getResponse();
});
console.log("end of function reached before httpGet will return");
// }
// }
}
FlightDelayIntentHandler();
到运行这段代码,别忘了npm install http
,然后是node test.js
。它产生
stormacq:~/Desktop/temp $ node test.js
end of function reached before httpGet will return
==> Answering:
I found something {
"args": {},
"data": "",
...
因此,关键是要等待 http get
到 return,然后再 return 对 Alexa 的响应。为此,我建议将您的 httpGet
函数修改为 return 承诺,而不是使用回调。
修改后的代码是这样的(我保留了你原来的代码作为注释)
const https = require('https');
async function httpGet(query) {
return new Promise( (resolve, reject) => {
var options = {
host: 'httpbin.org',
path: 'anything/' + query,
method: 'GET',
headers: {
'theId': 'myId'
}
};
var req = https.request(options, res => {
res.setEncoding('utf8');
var responseString = "";
//accept incoming data asynchronously
res.on('data', chunk => {
responseString = responseString + chunk;
});
//return the data when streaming is complete
res.on('end', () => {
console.log('==> Answering: ');
resolve(responseString);
});
//should handle errors as well and call reject()!
});
req.end();
});
}
async function FlightDelayIntentHandler() {
// canHandle(handlerInput) {
// return handlerInput.requestEnvelope.request.type === 'IntentRequest'
// && handlerInput.requestEnvelope.request.intent.name === 'MyIntent';
// },
// handle(handlerInput) {
// const request = handlerInput.requestEnvelope.request;
// if (request.dialogState != "COMPLETED"){
// return handlerInput.responseBuilder
// .addDelegateDirective(request.intent)
// .getResponse();
// } else {
// Make asynchronous api call, wait for the response and return.
var query = 'someTestStringFromASlot';
var result = await httpGet(query);
console.log("I found something " + result);
// return handlerInput.responseBuilder
// .speak('I found something' + result)
// .reprompt('test')
// .withSimpleCard('Hello World', 'test')
// .getResponse();
//});
console.log("end of function reached AFTER httpGet will return");
// }
// }
}
FlightDelayIntentHandler();
运行 此代码生成:
stormacq:~/Desktop/temp $ node test.js
==> Answering:
I found something{
"args": {},
"data": "",
...
end of function reached AFTER httpGet will return