在 SDK v2 上使用 Alexa 和 Lambda 进行 HTTP 请求,如何使其工作?
HTTP request with Alexa and Lambda on SDK v2, how to make it works?
我正在使用亚马逊提供的 ASK SDK v2 来为 Alexa 制作 Skill,但我遇到了架构问题:
首先,HTTP 请求非常有效,但我想 return 当且仅当我的 HTTP 请求完成时才说出响应,但我什至不知道这是否可能,因为"handle" 应该 return 的功能(查看评论):
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'MyIntent');
},
handle(handlerInput) {
var options = {
host: 'http://foo.com',
port: 80,
path: '/mypath',
method: 'GET'
};
var req = http.request(options, function(result){
result.on("end", function(){
//I would like to return speak here like that :
//return handlerInput.responseBuilder.speak("It works").withSimpleCard("MyTestApp", "It works").getResponse()
})
});
req.end();
//And I would like to remove this line to manage response in result.on("end", function(){}) above
return handlerInput.responseBuilder.speak("It works").withSimpleCard("MyTestApp", "It works").getResponse();
},
};
有什么办法解决这个问题吗?
我找到了官方制作方法:
1) 创建一个管理 http 请求和 return 承诺的新函数:
function httpGet(options) {
return new Promise(((resolve, reject) => {
const request = http.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
if (response.statusCode < 200 || response.statusCode >= 300) {
return reject(new Error(`${response.statusCode}: ${response.req.getHeader('host')} ${response.req.path}`));
}
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.on('error', function (error) {
reject(error);
});
request.end();
}));
}
2) 在 Intent 中,return 您调用 httpGet 函数的承诺:
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'MyIntent');
},
handle(handlerInput) {
var options = {
host: 'http://foo.com',
port: 80,
path: '/mypath',
method: 'GET'
};
return new Promise((resolve, reject) => {
httpGet(options).then((response) => {
resolve(handlerInput.responseBuilder.speak("It is done.").getResponse());
}).catch((error) => {
resolve(handlerInput.responseBuilder.speak('Thor is not available at the moment. Please try again later or contact your administrator.')
.getResponse());
});
});
},
};
这是正确的方法。我的示例基于 alexa petmatch sample.
我们也可以使用request模块调用API如下
const SearchIntentHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "SearchIntent"
);
},
handle(handlerInput) {
const query = handlerInput.requestEnvelope.request.intent.slots.SearchQuery.value;
return new Promise((resolve, reject) => {
getSearchResults(query).then((response) => {
resolve(handlerInput.responseBuilder.speak(response).getResponse());
}).catch((error) => {
resolve(handlerInput.responseBuilder.speak('This is not available at the moment.').getResponse());
});
});
}
};
function getSearchResults(query){
return new Promise((resolve, reject)=>{
let options = {
method: 'POST',
url: 'http://url.com',
headers: {'Cache-Control': 'no-cache','Content-Type': 'application/x-www-form-urlencoded' },
form: { text: query }
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
let data = body ? JSON.parse(body) : ""
return resolve(data);
});
});
}
一个Async/Await例子
- 将
handle
转换为异步函数。
- 等待你的承诺
示例:
const SomeIntentHandler = {
canHandle(handlerInput) {...},
async handle(handlerInput) {
return handlerInput.responseBuilder.speak(await promise).getResponse();
}
};
我正在使用亚马逊提供的 ASK SDK v2 来为 Alexa 制作 Skill,但我遇到了架构问题:
首先,HTTP 请求非常有效,但我想 return 当且仅当我的 HTTP 请求完成时才说出响应,但我什至不知道这是否可能,因为"handle" 应该 return 的功能(查看评论):
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'MyIntent');
},
handle(handlerInput) {
var options = {
host: 'http://foo.com',
port: 80,
path: '/mypath',
method: 'GET'
};
var req = http.request(options, function(result){
result.on("end", function(){
//I would like to return speak here like that :
//return handlerInput.responseBuilder.speak("It works").withSimpleCard("MyTestApp", "It works").getResponse()
})
});
req.end();
//And I would like to remove this line to manage response in result.on("end", function(){}) above
return handlerInput.responseBuilder.speak("It works").withSimpleCard("MyTestApp", "It works").getResponse();
},
};
有什么办法解决这个问题吗?
我找到了官方制作方法:
1) 创建一个管理 http 请求和 return 承诺的新函数:
function httpGet(options) {
return new Promise(((resolve, reject) => {
const request = http.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
if (response.statusCode < 200 || response.statusCode >= 300) {
return reject(new Error(`${response.statusCode}: ${response.req.getHeader('host')} ${response.req.path}`));
}
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.on('error', function (error) {
reject(error);
});
request.end();
}));
}
2) 在 Intent 中,return 您调用 httpGet 函数的承诺:
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'MyIntent');
},
handle(handlerInput) {
var options = {
host: 'http://foo.com',
port: 80,
path: '/mypath',
method: 'GET'
};
return new Promise((resolve, reject) => {
httpGet(options).then((response) => {
resolve(handlerInput.responseBuilder.speak("It is done.").getResponse());
}).catch((error) => {
resolve(handlerInput.responseBuilder.speak('Thor is not available at the moment. Please try again later or contact your administrator.')
.getResponse());
});
});
},
};
这是正确的方法。我的示例基于 alexa petmatch sample.
我们也可以使用request模块调用API如下
const SearchIntentHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "SearchIntent"
);
},
handle(handlerInput) {
const query = handlerInput.requestEnvelope.request.intent.slots.SearchQuery.value;
return new Promise((resolve, reject) => {
getSearchResults(query).then((response) => {
resolve(handlerInput.responseBuilder.speak(response).getResponse());
}).catch((error) => {
resolve(handlerInput.responseBuilder.speak('This is not available at the moment.').getResponse());
});
});
}
};
function getSearchResults(query){
return new Promise((resolve, reject)=>{
let options = {
method: 'POST',
url: 'http://url.com',
headers: {'Cache-Control': 'no-cache','Content-Type': 'application/x-www-form-urlencoded' },
form: { text: query }
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
let data = body ? JSON.parse(body) : ""
return resolve(data);
});
});
}
一个Async/Await例子
- 将
handle
转换为异步函数。 - 等待你的承诺
示例:
const SomeIntentHandler = {
canHandle(handlerInput) {...},
async handle(handlerInput) {
return handlerInput.responseBuilder.speak(await promise).getResponse();
}
};