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

How to make an asynchronous api call for Alexa Skill application with a Lambda function?

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

这是我的经纪人:

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

所以我怀疑我将不得不使用 promises 并在我的句柄函数前面放一个 "async" ?我对所有这一切都很陌生,所以我不知道这意味着什么,特别是考虑到我有两个不同的 return 值,一个是直接的,另一个是延迟的。我该如何解决?

提前致谢。

正如您所怀疑的,您的处理程序代码在异步调用 http.request 之前完成,因此 Alexa SDK 没有从 handle 函数接收到任何 return 值并将 return 对 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 到 return,然后再 return 对 Alexa 的响应。为此,我建议将您的 httpGet 函数修改为 return 承诺,而不是使用回调。

修改后的代码是这样的(我保留了你原来的代码作为注释)

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