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

在Express.js天气应用中,如何将https请求获取的lat/lon值代入wURL?

解决方案

核心问题拆解

  1. 请求时序错误:你同时发起了地理编码和天气请求,但天气请求完全依赖前者返回的经纬度,并行执行会导致天气请求拿到的参数是空值。
  2. 变量作用域问题:lat和lon是在地理请求的回调内部定义的局部变量,外部提前定义的wURL根本访问不到这些值。
  3. 未处理异常场景:如果输入的城市不存在,直接访问city[0].lat会触发报错,导致服务器崩溃。

修改后的完整代码

const express = require('express');
const https = require('node:https');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.urlencoded({ extended: true }));

app.get('/', function(req, res) {
  res.sendFile(__dirname + "/index.html");
});

app.post('/', function(req, res) {
  const query = req.body.cityName;
  const apiKey = "904f8e391a422fdf63b802aef88950c8";
  const units = "metric";
  const gURL = `https://api.openweathermap.org/geo/1.0/direct?q=${query}&limit=2&appid=${apiKey}`;

  // 先发起地理编码请求,拿到经纬度后再触发天气请求
  https.get(gURL, function(response) {
    let geoData = '';
    // 处理分块返回的数据,避免JSON解析失败
    response.on('data', function(chunk) {
      geoData += chunk;
    });

    response.on('end', function() {
      try {
        const city = JSON.parse(geoData);
        // 处理城市不存在的情况
        if (!city || city.length === 0) {
          return res.send('<h1>未找到指定城市,请重新输入</h1>');
        }
        const lat = city[0].lat;
        const lon = city[0].lon;
        // 拿到经纬度后再构建天气请求URL
        const wURL = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}&units=${units}`;

        // 发起天气请求
        https.get(wURL, function(weatherResponse) {
          let weatherData = '';
          weatherResponse.on('data', function(chunk) {
            weatherData += chunk;
          });

          weatherResponse.on('end', function() {
            const climate = JSON.parse(weatherData);
            const temp = climate.main.temp;
            const location = climate.name;
            const description = climate.weather[0].description;
            const icon = climate.weather[0].icon;
            const imgURL = `http://openweathermap.org/img/wn/${icon}@2x.png`;
            
            res.write(`<h1>The temperature in ${location} is ${temp} degC.</h1>`);
            res.write(`<p>The weather is currently ${description}</p>`);
            res.write(`<img src="${imgURL}">`);
            res.send();
          });
        }).on('error', function(err) {
          res.send(`<h1>获取天气数据失败:${err.message}</h1>`);
        });
      } catch (err) {
        res.send(`<h1>解析地理数据失败:${err.message}</h1>`);
      }
    });
  }).on('error', function(err) {
    res.send(`<h1>获取地理数据失败:${err.message}</h1>`);
  });
});

app.listen(3000, function() {
  console.log("Server is running on port:3000");
})

关键修改说明

  • 调整请求顺序:将天气请求嵌套在地理请求的end回调中,确保只有拿到有效经纬度后才发起天气请求。
  • 处理分块数据:原生https.get的data事件可能分多次返回数据,拼接后再解析JSON,避免因部分数据导致解析错误。
  • 添加异常处理:覆盖了城市不存在、请求失败、JSON解析失败等场景,防止服务器崩溃。
  • 优化URL写法:用模板字符串替代字符串拼接,提升代码可读性和可维护性。
  • 修正作用域:lat和lon在地理请求完成后定义,此时可直接用于构建天气请求URL。

进阶优化(可选)

如果觉得嵌套回调不够清晰,可以用Promise封装请求,再用async/await简化代码:

// 封装https.get为Promise
function fetchData(url) {
  return new Promise((resolve, reject) => {
    https.get(url, (response) => {
      let data = '';
      response.on('data', (chunk) => data += chunk);
      response.on('end', () => resolve(data));
    }).on('error', reject);
  });
}

// 修改post处理函数为async
app.post('/', async function(req, res) {
  try {
    const query = req.body.cityName;
    const apiKey = "904f8e391a422fdf63b802aef88950c8";
    const units = "metric";
    const gURL = `https://api.openweathermap.org/geo/1.0/direct?q=${query}&limit=2&appid=${apiKey}`;

    const geoData = await fetchData(gURL);
    const city = JSON.parse(geoData);
    if (!city || city.length === 0) {
      return res.send('<h1>未找到指定城市,请重新输入</h1>');
    }
    const lat = city[0].lat;
    const lon = city[0].lon;
    const wURL = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}&units=${units}`;

    const weatherData = await fetchData(wURL);
    const climate = JSON.parse(weatherData);
    const temp = climate.main.temp;
    const location = climate.name;
    const description = climate.weather[0].description;
    const icon = climate.weather[0].icon;
    const imgURL = `http://openweathermap.org/img/wn/${icon}@2x.png`;
    
    res.write(`<h1>The temperature in ${location} is ${temp} degC.</h1>`);
    res.write(`<p>The weather is currently ${description}</p>`);
    res.write(`<img src="${imgURL}">`);
    res.send();
  } catch (err) {
    res.send(`<h1>请求失败:${err.message}</h1>`);
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:35:50