WebClient 一调就报 WebException,HttpClient 却不抛异常?
这是最常踩的坑:用
WebClient请求一个返回 404 或 500 的 API,代码直接崩在
DownloadString上,抛出
WebException;而换成
HttpClient,
GetAsync照常返回
HttpResponseMessage,得手动检查
response.IsSuccessStatusCode才知道失败了。
WebClient把所有非 2xx 状态码当“异常”处理(哪怕 404 是你预期的业务结果)
HttpClient只在真正出问题时才抛
HttpRequestException(比如 DNS 失败、连接超时、服务器完全不可达) 这意味着:用
WebClient你得 try-catch 每次调用;用
HttpClient你可以统一判断
StatusCode,再分情况处理(如 401 跳登录、404 提示资源不存在)
为什么 new HttpClient() 用几次就卡死或报 SocketException?
这不是 bug,是误用。很多人照着示例写
using (var client = new HttpClient()),结果高并发下出现
SocketException: Only one usage of each socket address is normally permitted。
HttpClient设计为**长生命周期复用**,不是一次性的 —— 它背后维护 TCP 连接池 每次
new HttpClient()都新建连接池,频繁创建销毁会快速耗尽本地端口(TIME_WAIT 状态堆积)
WebClient虽也有类似风险,但因默认同步+低并发场景多,问题不明显;而
HttpClient异步高频使用时立刻暴露 正确做法:全局单例、DI 注入
IHttpClientFactory,或至少在类级别复用实例
上传文件、下载大文件,该选哪个?
看需求粒度。如果只是“把本地文件发到某个 URL”,
WebClient.UploadFile一行搞定;但如果要监控进度、设超时、加 token、支持断点续传、或上传流式数据(比如压缩中上传),
HttpClient是唯一选择。
WebClient:只支持完整文件路径上传,不支持
Stream或分块;无进度回调;不能设
Timeout(只能靠底层
WebRequest默认值)
HttpClient:可传
StreamContent、设
client.Timeout = TimeSpan.FromSeconds(60)、用
Progress<httpprogress></httpprogress>监听上传进度、支持
CancelToken中断 注意:
WebClient的
UploadFileAsync声称异步,但底层仍是同步 I/O 封装,无法真正释放线程;
HttpClient的异步才是真正的 awaitable I/O
新项目里还能用 WebClient 吗?
能,但不建议。.NET 官方已将
WebClient标记为 [Obsolete](https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient?view=net-8.0#remarks)(自 .NET 6 起警告,.NET 8+ 默认启用警告)。 它不支持 HTTP/2、不支持请求拦截器、不能配置消息处理器链(比如自动加 Auth Header)、无法集成 Polly 重试 所有现代库(如 Refit、Flurl)都基于
HttpClient构建;第三方认证库(Microsoft.Identity.Web)也只提供
HttpClient扩展 例外场景:写个临时控制台工具快速抓网页内容,
new WebClient().DownloadString(url)确实快——但这种“快”是以牺牲可维护性和未来扩展性换来的
真正容易被忽略的点是:异常语义差异不是风格偏好,而是设计契约。把 404 当异常捕获,等于把“资源不存在”当成程序错误;而把它作为正常响应处理,才能写出可预测、可观测、易测试的 HTTP 客户端逻辑。
