HttpClient必须复用,禁止单次new;异步调用必须await,禁用.Result/.Wait();POST JSON需正确设置Content-Type和序列化;超时与重试需手动配置,推荐Polly;边界问题需检查HttpClientHandler。
HttpClient 必须复用,别每次 new
创建 httpclient 实例开销不小,而且频繁 new 会导致端口耗尽(socketexception: address already in use),尤其在高并发服务里。.net core 2.1+ 已明确推荐单例或静态复用,不是“可以”,是“必须”。
- 用
static readonly HttpClient是最简单安全的做法(适合多数控制台、工具类场景) - ASP.NET Core 项目优先走 DI:注册为
AddHttpClient(),它内部自动管理生命周期和连接池 - 千万别在方法里写
using var client = new HttpClient();—— 这是典型踩坑写法,看似“及时释放”,实则破坏连接复用
异步调用必须 await,别用 .Result 或 .Wait()
HttpClient 所有核心方法(GetAsync、PostAsync、SendAsync)全是异步的,强行同步会死锁(尤其在 UI 线程或 ASP.NET 同步上下文里),错误现象常是线程卡住、请求无响应、CPU 100%。
- 所有调用必须用
await,对应方法签名也得是async Task<T> - 禁止出现
client.GetAsync(url).Result或.Wait(),哪怕只是临时调试也不行 - 如果非得在同步方法里调用(比如老代码改造),改用
GetAwaiter().GetResult()(仅限不得已,且确认无同步上下文)
POST 发 JSON 时 Content-Type 和序列化要配对
用 PostAsync 提交 JSON 却收到 400 Bad Request?大概率是 Content-Type 没设对,或序列化结果不符合 API 要求。
- 手动构造内容时:用
new StringContent(json, Encoding.UTF8, "application/json"),缺一不可 - 更推荐用
JsonContent.Create(obj)(.NET 5+),它自动设好类型和编码,还支持自定义JsonSerializerOptions - 注意:
JsonSerializer.Serialize默认不处理null字段,而很多 API 要求显式传null;必要时加DefaultIgnoreCondition = JsonIgnoreCondition.Never
超时和重试得自己控,HttpClient 不帮你兜底
HttpClient.Timeout 只管整个请求周期(DNS + 连接 + 发送 + 接收),不区分阶段;默认 100 秒,对多数 API 来说太长,且无法单独配置连接超时或重试逻辑。
- 设置合理超时:
client.Timeout = TimeSpan.FromSeconds(15);,避免线程长期挂起 - 重试不能靠
HttpClient自带——它没重试机制;要用Polly库,或手写简单指数退避(比如 5xx 或网络异常时 retry 2 次) - 注意:
HttpRequestException是总异常基类,具体原因得看.InnerException类型(WebException、SocketException、TaskCanceledException都可能)
真正麻烦的是跨域、证书验证、代理这些边界情况,它们不报错但行为诡异,比如本地能通、上服务器就失败——这时候得查 HttpClientHandler 的配置细节,而不是怪 API 不行。










