<p>必须设置 HTTP 超时并 URL 编码城市名:用 &http.Client{Timeout: 10 * time.Second} 避免卡死,城市名需 url.QueryEscape 处理空格和中文,否则请求 400 或挂起。</p>

怎么用 net/http 发起天气 API 请求不卡死
Go 默认的 http.Client 没设超时,遇到网络抖动或服务无响应,Get 会一直挂起,命令行工具就“假死”。必须手动加超时控制。
- 用
&http.Client{Timeout: 10 * time.Second}显式设置超时,别依赖默认值 - 天气 API(比如 OpenWeatherMap)要求带
appid查询参数,漏了会返回 401 错误:{"cod":"401","message":"Invalid API key"} - 请求 URL 中城市名要
url.QueryEscape处理空格和中文,否则 400;例如北京得传"Beijing"或%E5%8C%97%E4%BA%AC,不能直接拼"北京" - 别用
http.Get简写——它用的是全局默认 client,没法单独控超时或复用连接
解析天气 JSON 时 struct 字段为什么总为空
Go 的 json.Unmarshal 对字段可见性很敏感:只有首字母大写的导出字段才能被赋值。另外,API 返回的嵌套结构、字段名大小写、可选字段都容易踩坑。
- 检查 struct 字段是否以大写字母开头,比如
Temp✅,temp❌ - 用
json:"temp"标签对齐 API 字段名,OpenWeatherMap 的温度在main.temp,对应 struct 要写成Main struct { Temp float64 `json:"temp"` } - 如果某些字段可能不存在(如
rain.1h在没雨时压根不返回),字段类型别硬写float64,改用*float64或struct{ OneH *float64 `json:"1h,omitempty"` } - 用
json.RawMessage延迟解析不确定结构(比如不同天气服务返回的风向字段名不统一),避免一解就 panic
如何让命令行支持 -city 和 -unit 参数又不写一堆 flag 判断
手写 if os.Args[1] == "-city" 容易错位、难维护。flag 包是标准解法,但要注意默认值和类型转换的隐含行为。
- 用
flag.String("city", "", "城市名,必填"),然后必须调flag.Parse(),否则flag.Arg(0)这类老方式会漏参数 -
-unit推荐限定为metric/imperial,别接受自由字符串——API 只认这两个值,多一个就 400 - 必填参数(如
-city)要在flag.Parse()后立刻检查:if *city == "" { log.Fatal("缺少 -city 参数") },别等 HTTP 请求发出去才报错 - 别把
flag变量声明在函数里再传参,直接定义为包级变量更清晰,也方便测试 mock
本地调试时反复请求 API 被限流或返回缓存结果怎么办
OpenWeatherMap 免费版每分钟最多 1000 次,但更常见的是你改了代码重跑,API 却返回旧数据——其实是 DNS 或 HTTP 层缓存,不是 API 问题。
立即学习“go语言免费学习笔记(深入)”;
- 加请求头禁用缓存:
req.Header.Set("Cache-Control", "no-cache") - 开发时把 API 响应先写到本地文件,比如
curl -s "https://api.openweathermap.org/..." > mock.json,然后用os.ReadFile("mock.json")替代真实请求,省时间也防限流 - 环境变量管理 API key:
os.Getenv("WEATHER_API_KEY"),别硬编码;本地跑前执行export WEATHER_API_KEY=xxx - 注意时区:API 返回的
dt是 Unix 时间戳(UTC),用time.Unix(dt, 0).Local()转成本地时间,否则显示的“当前时间”可能差 8 小时
实际跑起来最常卡住的地方不是 JSON 解析,而是没设 HTTP 超时 + 忘了 URL 编码城市名——这两条一错,命令行就停在那儿不动,连错误都看不到。










