最稳方案是用 ihttpclientfactory 管理 httpclient,传 cancellationtoken 控制超时,校验返回 code=="200",反序列化 weatherapiresponse 根对象并缓存城市 id(key 带 exact/like 标识、过期 24 小时)。

用 HttpClient 调用和风天气免费接口最稳
和风天气(qweather.com)的「个人开发版」免费额度够用(1000次/天),响应快、字段全、有中文城市 ID 映射,比硬啃 OpenWeather 的英文坐标更省事。关键不是“能不能调”,而是“怎么避免 403 或空响应”。
常见错误现象:HttpRequestException 报 “Connection refused”;返回 JSON 里 code 是 "400" 或 "401";now.textDay 字段根本不存在——其实是因为没传 location 或 key 写错位置。
- 注册后在控制台拿到
key,别用测试 key(开头是HE2...),要正式申请的7位字母+数字形式 key - 城市 ID 必须用和风自己的
location,不是高德或百度的 adcode;查 ID 接口是https://geoapi.qweather.com/v2/city/lookup?location=北京&key=YOUR_KEY - 实际查天气用
https://devapi.qweather.com/v7/weather/now?location=101010100&key=YOUR_KEY,注意是devapi域名,不是api - 务必设
Accept: application/json请求头,否则某些代理会返回 HTML 错误页
JsonSerializer.Deserialize<weatherresponse></weatherresponse> 别直接套用返回结构
和风返回的 JSON 外层永远是 {"code":"200","now":{...},"lastUpdate":"..."},但很多人把 now 里的字段直接当成根对象反序列化,结果所有字段都是 null。
使用场景:你只想取温度、天气描述、体感温度,不关心预警或逐小时预报。
参数差异:C# 12 的源生成器(JsonSerializable)对嵌套对象支持还不成熟,老实用手动类 + [JsonPropertyName] 更可靠。
- 定义顶层类
WeatherApiResponse,包含string code、Now now、string lastUpdate -
Now类里字段名必须和 API 返回一致:string textDay(不是TextDay),string temp(不是Temperature) - 别忽略
code == "200"校验——哪怕 HTTP 状态码是 200,业务层仍可能失败 - 用
JsonSerializerOptions.PropertyNameCaseInsensitive = true避免大小写手抖
本地调试时 HttpClient 实例复用不当导致连接耗尽
新手常把 new HttpClient() 写在方法里,跑几次就报 SocketException: Too many open files。这不是天气 API 的问题,是 .NET 的 socket 生命周期没管好。
性能影响:单次请求延迟增加 50ms+;并发 10+ 就开始丢包;容器环境下可能触发 k8s liveness probe 失败。
- 全局只用一个
static readonly HttpClient,或注入IHttpClientFactory(推荐) - 如果用
IHttpClientFactory,注册时加超时:services.AddHttpClient("weather").ConfigurePrimaryHttpMessageHandler(_ => new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(5) }); - 别给
HttpClient设Timeout属性——它不生效;改用CancellationToken传给GetAsync - 不用
using var client = new HttpClient(),这是反模式
城市 ID 缓存不更新导致查到旧数据
用户输“南京”,你查一次 city/lookup 拿到 101190101,下次还用这个 ID——但如果用户实际想查“南京市江宁区”,而你缓存的是“南京市主城区”,结果温度差 2℃ 都算轻的。
容易踩的坑:把城市名当 key 存内存字典,但没处理“苏州”和“苏州市”的歧义;或缓存过期时间设成 7 天,而和风城市库每月都微调。
- 缓存 key 必须带精确匹配标识,比如
"lookup:南京:exact"(exact 表示全字匹配) vs"lookup:南京:like"(模糊) - 缓存过期设为 24 小时足够,和风明确说城市数据变更频率 ≤ 1 次/天
- 查不到 ID 时别 fallback 到默认城市,直接抛
ArgumentException($"未找到城市: {cityName}"),让用户修正输入 - 上线前用
curl "https://geoapi.qweather.com/v2/city/lookup?location=海口&key=xxx"手动验证返回是否含"id":"101310101"
真正麻烦的从来不是调通 API,而是城市名到 ID 的映射链路里,哪一环悄悄吞了异常、哪个缓存键少了个冒号、哪次 HttpClient 被 GC 提前回收了连接池。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










