全局变量在函数外显示undefined?API跨调用数据传递异常
问题原因
这是典型的异步操作执行顺序问题。https.get属于异步方法,发起请求后不会阻塞后续代码运行:你定义的console.log和url2会在第一个API的响应返回前就执行,此时latitude和longitude还没被赋值,自然处于undefined状态。只有当API响应完成后,response.on("data")里的回调函数才会触发,给这两个变量赋值。
解决方案
下面提供几种可行的修复方式:
方式1:嵌套回调(最直接的修改)
将第二个API的调用逻辑放到第一个API的回调内部,确保拿到坐标后再执行后续操作:
var latitude, longitude; var cityn = req.body.cityname; const appid = "..."; var unit = "metric"; const url1 = "https://api.openweathermap.org/geo/1.0/direct?q=" + cityn + "&limit=5&appid=" + appid; https.get(url1, function(response) { // 注意:API响应可能分块返回,需要拼接完整数据 let rawData = ""; response.on("data", function(chunk) { rawData += chunk; }); response.on("end", function() { const CityDetails = JSON.parse(rawData); latitude = CityDetails[0].lat; longitude = CityDetails[0].lon; console.log(latitude); // 此时已赋值 console.log(longitude); // 此时已赋值 // 在这里发起第二个API请求 const url2 = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${appid}&units=${unit}`; https.get(url2, function(weatherResponse) { let weatherRawData = ""; weatherResponse.on("data", function(chunk) { weatherRawData += chunk; }); weatherResponse.on("end", function() { const weatherDetails = JSON.parse(weatherRawData); // 处理天气数据的后续逻辑 }); }); }); });
方式2:Promise封装(避免回调地狱)
把异步请求封装为Promise,让异步逻辑更清晰:
var cityn = req.body.cityname; const appid = "..."; var unit = "metric"; // 封装获取城市坐标的Promise function getCityCoords(cityName) { return new Promise((resolve, reject) => { const url1 = `https://api.openweathermap.org/geo/1.0/direct?q=${cityName}&limit=5&appid=${appid}`; https.get(url1, function(response) { let rawData = ""; response.on("data", chunk => rawData += chunk); response.on("end", () => { try { const cityData = JSON.parse(rawData); resolve({ lat: cityData[0].lat, lon: cityData[0].lon }); } catch (err) { reject(err); } }); response.on("error", reject); }); }); } // 封装获取天气数据的Promise function getWeatherData(lat, lon) { return new Promise((resolve, reject) => { const url2 = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${appid}&units=${unit}`; https.get(url2, function(response) { let rawData = ""; response.on("data", chunk => rawData += chunk); response.on("end", () => { try { const weatherData = JSON.parse(rawData); resolve(weatherData); } catch (err) { reject(err); } }); response.on("error", reject); }); }); } // 链式调用处理异步流程 getCityCoords(cityn) .then(coords => { console.log(coords.lat, coords.lon); return getWeatherData(coords.lat, coords.lon); }) .then(weatherInfo => { // 处理最终的天气数据 console.log(weatherInfo); }) .catch(err => { console.error("请求出错:", err); });
方式3:async/await(最简洁的写法)
基于Promise封装,用async/await让异步代码看起来像同步代码:
var cityn = req.body.cityname; const appid = "..."; var unit = "metric"; // 复用上面定义的getCityCoords和getWeatherData函数 async function fetchCityWeather() { try { const coords = await getCityCoords(cityn); console.log(coords.lat, coords.lon); const weatherInfo = await getWeatherData(coords.lat, coords.lon); // 处理天气数据的业务逻辑 console.log(weatherInfo); } catch (err) { console.error("请求异常:", err); } } // 执行异步函数 fetchCityWeather();
注意:原代码中直接解析
response.on("data")的回调参数可能会出现JSON解析错误,因为API响应可能分块返回,上面的方案都处理了这个问题,确保拼接完整数据后再解析。
内容的提问来源于stack exchange,提问作者Nikhil Thakur
相关产品推荐
相关产品推荐

