使用HTTP调用WeatherStack API却被识别为HTTPS的问题排查
WeatherStack API请求异常排查
代码示例
我在React顶层Weather组件中使用以下代码,通过create-react-app在localhost:3000发起客户端请求:
const fetchWeatherData = async () => { try { // 注意:此处为示例API密钥,非真实密钥 const response = await fetch('http://api.weatherstack.com/current?access_key=19a9566d7a5dbaeb4a467035cb59&query=Bozeman'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching weather data:', error); throw error; } };
错误响应
请求返回的Promise对象错误如下:{success: false, error: {…}}
错误详情:
- error:
- code: 105
- info: "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption."
- type: "https_access_restricted"
问题描述
我耗时数小时排查,始终搞不懂为什么明明是HTTP请求,却被识别成HTTPS请求。该代码偶尔(约10%概率)能正常返回博兹曼的天气数据。这是浏览器/本地开发中fetch API的问题?还是WeatherStack在引导用户升级付费套餐?
目前我尝试用Node+Express搭建后端代理请求,但不确定这是不是正确的解决方案。
已尝试的方案
- 深入研究JavaScript fetch API,确认HTTP请求是否被自动转为HTTPS
- 正在尝试:通过Node + Express将客户端请求代理到服务器
问题分析与解决方案
核心原因
- WeatherStack自动跳转机制:免费套餐不支持HTTPS,但WeatherStack可能会将HTTP请求自动重定向到HTTPS地址,触发权限限制。偶尔成功的情况大概率是重定向机制临时波动导致的。
- 浏览器安全策略影响:部分现代浏览器会通过HSTS等机制自动将HTTP请求升级为HTTPS,如果WeatherStack的域名被浏览器标记为强制HTTPS,就会触发跳转,进而触发套餐限制。
正确解决方案:使用后端代理
你现在尝试的Node+Express代理方案完全正确,原因有两点:
- 后端发起HTTP请求不受浏览器安全策略限制,能直接访问WeatherStack的HTTP接口
- 可以避免API密钥暴露在前端代码中(当前前端硬编码密钥的做法存在安全风险,密钥被滥用可能导致额外限制)
代理实现示例
// 服务器端(Node+Express)代码示例 const express = require('express'); const fetch = require('node-fetch'); const app = express(); const port = 5000; // 配置CORS,允许前端localhost:3000访问 app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); res.header('Access-Control-Allow-Methods', 'GET'); next(); }); // 代理天气请求 app.get('/api/weather', async (req, res) => { try { const query = req.query.city || 'Bozeman'; const apiKey = '你的真实API密钥'; // 建议存到环境变量中 const response = await fetch(`http://api.weatherstack.com/current?access_key=${apiKey}&query=${query}`); const data = await response.json(); res.json(data); } catch (error) { res.status(500).json({ error: 'Failed to fetch weather data' }); } }); app.listen(port, () => { console.log(`Proxy server running on http://localhost:${port}`); });
前端修改后的请求代码:
const fetchWeatherData = async () => { try { const response = await fetch('http://localhost:5000/api/weather?city=Bozeman'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching weather data:', error); throw error; } };
额外注意事项
- 务必将API密钥存储在后端环境变量中,不要硬编码在代码里
- 如果代理后仍出现问题,检查WeatherStack的套餐请求次数、地域等限制规则
内容的提问来源于stack exchange,提问作者Josiah Schwahn
相关产品推荐
相关产品推荐

