Node/Express天气应用API数据传递问题:GeoNames数据无法传入WeatherBit
天气日志Web应用API数据传递问题
我用Node.js、Express、Cors和Body Parser开发天气日志Web应用,通过Fetch API调用在线接口。已经写完server.js、index.html、app.js,server.js包含Express服务及中间件,app.js实现核心功能。我想先通过GeoNames API获取城市的经纬度,再把经纬度传给WeatherBit API获取对应天气,但现在打印最终数据时返回undefined,没法完成API间的数据传递。
现有代码
Index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Weather Journal</title> </head> <body> <div id="app"> <div class="holder headline">Weather Journal App</div> <form id="userInfo"> <div class="holder zip"> <label for="zip">Enter City here</label> <input type="text" id="city" placeholder="enter city here" required> </div> <div class="holder feel"> <label for="date">Enter departure date</label> <input type="datetime-local" id="date" required> <button id="submitBtn" type="submit"> Generate </button> </div> </form> <div class="holder entry"> <div class="title">Most Recent Entry</div> <div id="entryHolder"> <div id="lat"></div> <div id="lng"></div> <div id="countryName"></div> <div id="temp"></div> </div> </div> </div> <script src="app.js" type="text/javascript"></script> </body> </html>
app.js
const geoURL = "http://api.geonames.org/searchJSON?"; const geoUsername = `rohanasif1990`; const weatherURL = "https://api.weatherbit.io/v2.0/forecast/daily?" const weatherKey = "20028a8267a24bba9a807362767bc4a7" let d = new Date(); let newDate = d.getMonth() + 1 + "." + d.getDate() + "." + d.getFullYear(); const submitBtn = document.getElementById("submitBtn"); submitBtn.addEventListener("click", (e) => { e.preventDefault(); const city = document.getElementById("city").value; if (city !== "") { getCity(geoURL, city, geoUsername) .then(function (data) { getWeather(weatherURL, weatherKey, data["geonames"][0]['lat'], data["geonames"][0]['lng']) }).then(weatherData => { postWeatherData("/addWeather", { temp: weatherData }) }).then(function () { receiveWeatherData() }).catch(function (error) { console.log(error); alert("Invalid city"); }) } }) const getCity = async (geoURL, city, geoUsername) => { const res = await fetch(`${geoURL}q=${city}&username=${geoUsername}`); try { const cityData = await res.json(); return cityData; } catch (error) { console.log("error", error); } } const postWeatherData = async (url = "", data = {}) => { const response = await fetch(url, { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ temp: data.temp }) }); try { const newData = await response.json(); return newData; } catch (error) { console.log(error); } } const receiveWeatherData = async () => { const request = await fetch("/allWeather"); try { const allData = await request.json() document.getElementById("temp").innerHTML = allData.temp; } catch (error) { console.log("error", error) } } const getWeather = async (weatherURL, weatherKey, lat, lon) => { const res = await fetch(`${weatherURL}&lat=${lat}&lon=${lon}&key=${weatherKey}`); try { const weatherData = await res.json(); return weatherData; } catch (error) { console.log("error", error); } }
server.js
// Setup empty JS object to act as endpoint for all routes cityData = {}; weatherData = {}; picturesData = {}; // Require Express to run server and routes const express = require('express'); const bodyParser = require('body-parser'); const cors = require('cors'); // Start up an instance of app const app = express(); /* Middleware */ //Here we are configuring express to use body-parser as middle-ware. app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // Cors for cross origin allowance app.use(cors()) // Initialize the main project folder app.use(express.static('website')); app.get("/all", function sendData(req, res) { res.send(cityData); }) app.get("/allWeather", function sendWeather(req, res) { res.send(weatherData); }) app.get("allPictures", function sendPictures(req, res) { res.send(picturesData); }) app.post("/add", (req, res) => { projectData['lat'] = req.body.lat; projectData['lng'] = req.body.lng; projectData['countryName'] = req.body.countryName res.send(cityData); }) app.post("/addWeather", (req, res) => { weatherData['temp'] = req.body.temp; res.send(weatherData); }) app.post("/addPicture", (req, res) => { picturesData['pic'] = req.body.pic; res.send(picturesData); }) // Setup Server app.listen(3000, () => { console.log("App listening on port 3000") console.log("Go to http://localhost:3000") })
问题修复点
1. Promise链中断导致数据传递失败
第一个.then中调用getWeather后未返回Promise,导致后续.then拿到undefined。修改如下:
getCity(geoURL, city, geoUsername) .then(function (data) { // 返回getWeather的Promise,保证链的连续性 return getWeather(weatherURL, weatherKey, data["geonames"][0]['lat'], data["geonames"][0]['lng']) }).then(weatherData => { postWeatherData("/addWeather", { temp: weatherData }) })
2. WeatherBit API请求URL格式错误
weatherURL末尾带有?,拼接参数后会生成非法格式?&lat=...,需要去掉末尾的?:
// 修改前 const weatherURL = "https://api.weatherbit.io/v2.0/forecast/daily?" // 修改后 const weatherURL = "https://api.weatherbit.io/v2.0/forecast/daily"
3. 未正确提取WeatherBit返回的温度数据
WeatherBit返回的是多日预报对象,需提取具体温度字段(比如当日气温),而非直接传递整个对象:
.then(weatherData => { // 取第一天的预报温度,可根据需求调整日期 const temp = weatherData.data[0].temp; postWeatherData("/addWeather", { temp: temp }) })
4. Server路由缺失斜杠
allPictures路由的GET请求缺少开头的/,导致无法访问:
// 修改前 app.get("allPictures", function sendPictures(req, res) { // 修改后 app.get("/allPictures", function sendPictures(req, res) {
5. Server中未定义的projectData
/add路由使用了未声明的projectData,应替换为已定义的cityData:
app.post("/add", (req, res) => { cityData['lat'] = req.body.lat; cityData['lng'] = req.body.lng; cityData['countryName'] = req.body.countryName res.send(cityData); })
内容的提问来源于stack exchange,提问作者Rohan Asif
相关产品推荐
相关产品推荐

