【问题标题】:How to make an asynchronous api call for Alexa Skill application with a Lambda function?如何使用 Lambda 函数对 Alexa Skill 应用程序进行异步 api 调用?
【发布时间】:2019-01-16 18:10:05
【问题描述】:

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

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

提前谢谢你。

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2017-02-16
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-21
      • 2016-09-18
      相关资源
      最近更新 更多