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

Node.js HTTPS调用返回undefined问题(AWS Alexa技能场景)

问题分析与解决方案

你遇到的问题核心是异步操作的时序问题。你的getCall()函数发起了一个异步的HTTPS请求去获取ThingSpeak的数据,但函数本身会立即返回,不会等待请求完成。当Alexa的GetNewFactHandler执行时,请求还没结束,pooltemp自然是undefined。而第二次调用时AWS Lambda的函数实例被复用,此时之前的请求已经完成,pooltemp有了值,所以能正常返回。

全局变量pooltemp在Lambda环境里非常不可靠——函数实例会被AWS暂存一段时间,但你无法控制这个时长,而且并发请求时还可能导致值混乱。正确的做法是在每次handler处理请求时,主动等待异步请求完成,而不是依赖全局变量。

修复方案

1. 将getCall()改为返回Promise

把异步的HTTPS请求包装成Promise,这样我们就能在handler里用await等待数据返回:

function getCall() {
  return new Promise((resolve, reject) => {
    var options = {
      protocol: 'https:',
      host: 'api.thingspeak.com',
      path: '/channels/494722/feeds.json?api_key=9HILOGJ9P2HRDPNO&results=1',
      method: 'GET'
    };

    var getReq = https.request(options, function(res) {
      console.log("\nstatus code: ", res.statusCode);
      var jsonData = '';
      res.on('data', function(data) {
        jsonData += data;
      });
      res.on('end', function() {
        console.log('We have all the data');
        var result = JSON.parse(jsonData);
        console.log('data: ', result);
        console.log('Pool temperature: ', result.feeds[0].field1);
        // 返回温度值
        resolve(result.feeds[0].field1);
      });
    });

    getReq.end();
    getReq.on('error', function(err) {
      console.log("Error: ", err);
      // 请求失败时返回错误
      reject(err);
    });
  });
}

2. 修改GetNewFactHandler的handle方法为异步函数

在handle方法里使用await获取温度,并且去掉全局变量pooltemp:

const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'LaunchRequest' ||
      (request.type === 'IntentRequest' && request.intent.name === 'GetNewFactIntent');
  },
  async handle(handlerInput) {
    try {
      // 等待获取温度
      const pooltemp = await getCall();
      let factIndex;
      const factArr = data;

      // 修正你的温度判断逻辑(原来的`15 < pooltemp == pooltemp < 20`写法是错误的)
      if (pooltemp <= 15) {
        factIndex = 0;
      } else if (pooltemp > 15 && pooltemp < 20) {
        factIndex = 1;
      } else if (pooltemp >= 20 && pooltemp < 25) {
        factIndex = 2;
      } else if (pooltemp >= 25) {
        factIndex = 3;
      }

      const randomFact = factArr[factIndex];
      const speechOutput = 'Hold on a second, I will check for you.<break time="1s"/>Today it is ' + pooltemp + ' degrees in the pool. ' + randomFact;
      
      return handlerInput.responseBuilder
        .speak(speechOutput)
        .withSimpleCard(SKILL_NAME, randomFact)
        .getResponse();
    } catch (err) {
      // 请求失败时返回错误提示
      console.error('Failed to get pool temperature:', err);
      return handlerInput.responseBuilder
        .speak('Sorry, I couldn\'t check the pool temperature right now. Please try again later.')
        .getResponse();
    }
  },
};

3. 移除全局变量和提前调用的getCall()

删掉这两行:

var pooltemp;
getCall();

关键修改点说明

  • 用Promise封装异步请求,确保我们能等待数据返回后再处理逻辑。
  • 使用async/await让异步代码看起来像同步代码,避免回调地狱。
  • 去掉不可靠的全局变量,每次请求都主动获取最新温度。
  • 修正了你原来的温度判断逻辑(15 < pooltemp == pooltemp < 20这种写法不符合JS语法,会导致错误的判断结果)。
  • 添加了错误处理,当ThingSpeak请求失败时给用户友好提示。

这样修改后,每次Alexa处理请求时都会先等待温度数据获取完成,再也不会出现第一次调用返回undefined的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:19:45