如何使用Lambda函数对Alexa Skill应用程序进行异步api调用?

时间:2018-08-09 10:08:54

标签: node.js aws-lambda alexa alexa-skills-kit alexa-slot

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

这是我的处理程序:

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

所以我怀疑我将不得不使用Promise并在我的handle函数前面放置“异步”吗?我对这一切都很陌生,所以我不知道这意味着什么,尤其是考虑到我有两个不同的返回值,一个是直接返回值,另一个是延迟值。我该如何解决?

谢谢。

1 个答案:

答案 0 :(得分:2)

您怀疑,您的处理程序代码在异步调用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