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
相关产品推荐
相关产品推荐

