不能每次请求都 new httpclient,因其设计为长期复用,频繁创建销毁会导致端口耗尽、dns 不刷新、tls 握手开销激增,引发 socketexception 或超时;正确做法是全局复用,asp.net core 优先用 addhttpclient(),其他场景用 static readonly 或单例。

别用 WebClient 或 HttpWebRequest 写新代码 —— HttpClient 是唯一推荐的现代方式,但直接 new 一个就用,大概率踩坑。
为什么不能每次请求都 new HttpClient?
HttpClient 被设计为长期复用的类型,内部维护连接池和 DNS 缓存。频繁 new + dispose 会导致端口耗尽、DNS 不刷新、TLS 握手开销激增 —— 常见现象是程序跑几小时后突然大量 SocketException 或超时。
- 正确做法:整个应用生命周期内只创建一个(或少数几个)
HttpClient实例 - ASP.NET Core 用户优先用
IServiceCollection.AddHttpClient()注册,由 DI 容器管理生命周期 - 控制台或 WinForms 等场景,声明为
static readonly字段,或封装成单例服务 - 不要在 using 块里包裹
HttpClient—— 这是反模式
POST JSON 数据时 Content-Type 总是错?
手动拼接字符串再设 Content-Type 很容易漏掉字符编码或类型拼写错误,比如写成 "application/json" 却没带 charset=utf-8,或误用 StringContent 而没指定编码。
- 推荐用
JsonContent.Create(obj)(.NET 6+),自动处理序列化、UTF-8 编码和Content-Type: application/json; charset=utf-8 - .NET 5 及更早版本可用
new StringContent(JsonSerializer.Serialize(obj), Encoding.UTF8, "application/json") - 避免用
FormUrlEncodedContent发 JSON —— 它会把整个 JSON 当作一个表单字段值,后端收不到结构化数据
怎么安全地处理超时和重试?
HttpClient.Timeout 是整个请求的总时限,包括 DNS 查询、连接、发送、等待响应头 —— 但它不能中断正在读取响应体的大文件流。而且它不支持指数退避重试。
- 单次请求超时:用
CancellationTokenSource控制,比设置Timeout属性更灵活 - 需要重试:别自己 while 循环 sleep,改用
Polly库的AddPolicyHandler(配合IHttpClientFactory) - 注意:重试 GET 是安全的,但重试 POST 可能造成重复提交,必须由后端幂等性保障
- 大文件上传/下载建议禁用
HttpClient.Timeout,改用CancellationToken配合进度回调
证书验证失败或代理问题怎么调试?
开发时遇到 HttpRequestException: The SSL connection could not be established 或请求卡在 CONNECT 阶段,通常不是代码问题,而是环境配置缺失。
- 忽略证书验证(仅限测试):配置
HttpClientHandler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true—— 生产环境绝对禁止 - 走公司代理:检查系统代理设置是否生效;.NET 6+ 默认读取
HTTP_PROXY环境变量,也可显式传入new HttpClientHandler { UseProxy = true } - 调试技巧:用
curl -v对比相同 URL,确认是代码问题还是网络策略问题 - Linux 容器中缺少根证书?需安装
ca-certificates包,并确保DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=0
真正麻烦的从来不是“怎么发请求”,而是连接复用策略、异常传播路径、跨平台证书信任链这些隐性依赖 —— 它们不会报编译错误,但会在高并发、容器化、混合云场景里突然爆发。











