You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Alexa Skill调用第三方API报错:Session ended with reason: ERROR排查

解决Alexa Skill调用第三方API触发Session ERROR的问题

我看你在开发Alexa Skill时调用numbersapi的API,遇到了CloudWatch日志显示Session ended with reason: ERROR的问题,还拿不准是NumberIntentHandler还是httpGet函数出了问题。咱们来拆解下你提供的两段代码的问题,再给出修复方案:

第一个版本(带Async/Promise)的核心问题

你的httpGet是异步函数(返回Promise),但在handle方法里直接用const myResult = httpGet(options);接收结果——这时候myResult只是一个未完成的Promise对象,不是API返回的实际文本。Alexa的handler要么同步返回响应,要么返回一个Promise来处理异步逻辑,你直接把Promise赋值给speechText,必然会导致Alexa无法解析响应,触发Session错误。

另外httpGet里还有个小bug:判断响应状态码时用了response < 200 || response > 299,但这里的response是HTTP响应对象,不是状态码,应该用response.statusCode。

第二个版本(移除Async/Await/Promise)的核心问题

你改成回调模式后,handle方法的逻辑完全走偏了:你把构建响应的代码放在了httpGet的回调里,但Alexa的handle方法需要立即返回响应或返回Promise,而你的代码里handle没有任何返回值——因为httpGet是异步的,回调执行时handle早就结束了,Alexa收不到响应,直接触发ERROR。

修正后的完整代码方案

我们需要让handle方法支持异步逻辑,同时正确处理API调用的成功/失败场景:

修正后的NumberIntentHandler

const NumberIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
      handlerInput.requestEnvelope.request.intent.name === 'NumberIntent';
  },
  // 将handle声明为async函数,支持await处理异步操作
  async handle(handlerInput) {
    let slotNum = handlerInput.requestEnvelope.request.intent.slots.number.value;
    const myRequest = parseInt(slotNum);
    console.log('NumberIntentHandler myRequest: ', myRequest);
    const options = `http://numbersapi.com/${myRequest}`;
    console.log('NumberIntentHandler options: ', options);

    try {
      // 用await等待httpGet的Promise完成,拿到实际API返回值
      const myResult = await httpGet(options);
      console.log("sent : " + options);
      console.log("received : " + myResult);
      const speechText = myResult;
      console.log('speechText: ', speechText);

      return handlerInput.responseBuilder
        .speak(speechText)
        .withSimpleCard('Here is your fact: ', speechText)
        .getResponse();
    } catch (error) {
      // 捕获API调用失败的情况,返回友好提示
      console.error('API调用失败:', error);
      const errorSpeech = "抱歉,我暂时无法获取这个数字的相关信息,请稍后再试。";
      return handlerInput.responseBuilder
        .speak(errorSpeech)
        .withSimpleCard('出错了', errorSpeech)
        .getResponse();
    }
  },
};

修正后的httpGet函数

const http = require('http'); // 别忘了引入http模块!

async function httpGet(options) {
  console.log(`~~~~~~~~~ httpGet ~~~~~~~~~`);
  console.log(`~~~~~${JSON.stringify(options)}~~~~~`);
  return new Promise((resolve, reject) => {
    const request = http.get(options, (response) => {
      // 修复状态码判断:使用response.statusCode
      if (response.statusCode < 200 || response.statusCode > 299) {
        reject(new Error('加载失败,状态码: ' + response.statusCode));
      }
      const body = [];
      response.on('data', (chunk) => body.push(chunk));
      response.on('end', () => resolve(body.join('')));
    });

    request.on('error', (err) => reject(err));
    request.end();
  });
}

关键修复点总结

  1. 让handle支持异步:把handle声明为async函数,用await等待API调用完成,确保拿到实际数据再构建响应。
  2. 添加错误捕获:用try/catch处理API调用失败的情况,避免Session直接报错,同时给用户友好提示。
  3. 修复状态码判断:把response改为response.statusCode,正确识别HTTP响应状态。
  4. 确保引入http模块:如果你的代码里没加const http = require('http');,一定要补上,否则会触发模块未找到的错误。

另外建议你去CloudWatch的日志组里查看更详细的错误堆栈——比如如果是Promise未处理、模块缺失这类问题,日志里会有明确的报错信息,能帮你更快定位问题。

内容的提问来源于stack exchange,提问作者Hackbrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:08:25