如何使用 Lambda 函数对 Alexa 技能应用程序进行异步 API 调用?



我想从 Lambda 函数调用一个 api。我的处理程序由包含两个所需插槽的意图触发。因此,我事先不知道我是否会返回Dialog.Delegate指令或我从 api 请求的响应。如何在调用意图处理程序时承诺这些返回值?

这是我的处理程序:

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

所以我怀疑我将不得不使用承诺并在我的句柄函数前面放一个"异步"?我对所有这些都很陌生,所以我不知道这有什么影响,特别是考虑到我有两个不同的返回值,一个是直接的,另一个是延迟的。我将如何解决这个问题?

提前谢谢你。

正如您所怀疑的那样,您的处理程序代码在异步调用 http.request 之前完成,因此 Alexa SDK 不会收到来自handle函数的返回值,并且会向 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返回,然后再向Alexa返回响应。为此,我建议修改您的httpGet函数以返回一个承诺,而不是使用回调。

修改后的代码是这样的(我保留了您的原始代码作为注释(

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

最新更新