Express+Axios调用OpenWeatherMap API遇连接拒绝及响应头错误求助
我来帮你拆解这两个问题,都是代码里的小细节导致的:
1. Error: connect ECONNREFUSED 127.0.0.1:80 问题
这个错误的核心原因是你的OpenWeatherMap API URL写错了——少了协议后的双斜杠!原代码里写的是http:api.openweathermap.org/...,正确的格式应该是http://api.openweathermap.org/...(更推荐用HTTPS,改成https://更安全)。
因为缺少//,Axios会把这个URL当成相对路径处理,默认请求本地服务器的80端口,这就导致了连接被拒绝的错误。而浏览器访问时会自动补全协议后的双斜杠,所以能正常返回数据,但Axios不会做这个自动补全,必须手动写对完整URL。
修正后的getWeather函数URL应该是:
url:`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.WAPI}`
2. Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 问题
这个错误是因为你的路由逻辑里,同一个请求被发送了两次响应。
看你的路由代码:
if (lat && lon) { // ... 这里会执行res.json(...)返回响应 } res.send("no location specified")
当lat和lon存在时,你先发送了res.json()响应,但代码不会停止执行,会继续走到后面的res.send(),这就违反了HTTP协议一个请求对应一个响应的规则,导致报错。
解决方法很简单,有两种可选方案:
方案一:用return终止后续代码执行
app.get("/", cors(), async (req, res) => { const lat: number = + req.query.lat; const lon: number = + req.query.lon; if (lat && lon) { const entry = cach.filter(e => e.lat === lat && e.lon === lon); if (entry.some(e => (Date.now() - e.last_updated < 36000000))) { return res.json(entry[0]); // 加上return,阻止后续代码执行 } else { return res.json(await getWeather(lat, lon)); // 同样加return } } res.send("no location specified") });
方案二:用else分支包裹默认响应
app.get("/", cors(), async (req, res) => { const lat: number = + req.query.lat; const lon: number = + req.query.lon; if (lat && lon) { const entry = cach.filter(e => e.lat === lat && e.lon === lon); if (entry.some(e => (Date.now() - e.last_updated < 36000000))) { res.json(entry[0]); } else { res.json(await getWeather(lat, lon)); } } else { // 把默认响应放到else分支里 res.send("no location specified") } });
额外小建议
你的getWeather函数里的catch块只打印了错误,但没有把错误信息反馈给客户端,而且缓存逻辑里没有把新获取的数据加入缓存(这样缓存永远不会更新)。可以优化一下:
async function getWeather(lat: number, lon: number) { try { const res = await axios({ url:`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.WAPI}`, method:"GET" }); const data = res.data; // 返回带缓存时间的结构,方便后续缓存判断 return { lat, lon, last_updated: Date.now(), ...data }; } catch (error){ console.error('获取天气数据失败:', error); // 抛出错误,让路由层处理并返回给客户端 throw error; } }
然后在路由里加上错误捕获,避免服务器崩溃:
app.get("/", cors(), async (req, res) => { try { const lat: number = + req.query.lat; const lon: number = + req.query.lon; if (lat && lon) { const entry = cach.filter(e => e.lat === lat && e.lon === lon); if (entry.some(e => (Date.now() - e.last_updated < 36000000))) { return res.json(entry[0]); } else { const weatherData = await getWeather(lat, lon); // 将新数据加入缓存 cach.push(weatherData); return res.json(weatherData); } } res.send("no location specified") } catch (err) { res.status(500).json({error: '获取天气数据失败,请稍后重试'}); } });
内容的提问来源于stack exchange,提问作者JohanRH
相关产品推荐
相关产品推荐

