如何使用Lambda函数对Alexa Skill应用程序进行异步api调用? [英] How to make an asynchronous api call for Alexa Skill application with a Lambda function?

查看:119
本文介绍了如何使用Lambda函数对Alexa Skill应用程序进行异步api调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从Lambda函数调用api。我的处理程序由包含两个必需插槽的意图触发。因此,我事先不知道我是否要返回 Dialog.Delegate 指令或我对api请求的响应。

I want to call an api from a Lambda function. My handler is triggered by an intent which includes two required slots. Therefore I don't know in advance whether I will be returning a Dialog.Delegate directive or my response from the api request. How do I promise these return values by the time the intent handler is called?

这是我的处理程序:

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

这是我的帮助程序,它发出请求:

This is my helper function which makes the request:

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

所以我怀疑我将不得不使用Promise并在其中添加异步我的句柄功能的前面?我对这一切都很陌生,所以我不知道这意味着什么,尤其是考虑到我有两个不同的返回值,一个是直接的,另一个是延迟的。我该怎么解决?

So I suspect I will have to use promises and put an "async" in front of my handle function? I am very new to all of this so I don't know the implications of this, especially considering the fact that I have two different return values, one directly and the other one delayed. How would I solve this?

谢谢。

推荐答案

您怀疑,您的处理程序代码在异步调用http.request之前已经完成,因此Alexa SDK没有从 handle 函数接收任何返回值,并且将返回无效响应

As you suspected, your handler code is finishing before the asynchronous call to http.request, hence the Alexa SDK receives no return value from the handle function and will return an invalid response to Alexa.

我稍微修改了您的代码,以在笔记本电脑上本地运行它来说明问题:

I slightly modified your code to run it locally on a laptop to illustrate the issue :

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 。它产生

To run this code, do not forget npm install http , then node test.js. It produces

stormacq:~/Desktop/temp $ node test.js
end of function reached before httpGet will return
==> Answering:
I found something {
  "args": {},
  "data": "",
... 

所以,关键是要等 http get 返回之后再返回对Alexa的响应。为此,我建议修改您的 httpGet 函数以使用回调返回承诺。

So, the key is to wait for http get to return before to return a response to Alexa. For that, I propose to modify your httpGet function to return a promise instead using callbacks.

修改后的代码就像这个(我保留了您的原始代码作为注释)

Modified code is like this (I kept your original code as comment)

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函数对Alexa Skill应用程序进行异步api调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆