推荐使用 HttpClient 发送 GET 请求,它支持异步、连接池、DNS 缓存和响应压缩;需作为单例复用,显式设置超时,避免 .Result/.Wait() 死锁;HttpRequestMessage+SendAsync 适用于复杂头或重试场景;WebClient 仅限 .NET Framework 4.0 极简脚本;HttpWebRequest 已过时,仅用于教学或兼容。

用 HttpClient 发送 GET 是当前推荐方式
它支持异步、可复用、内置连接池,且默认启用 DNS 缓存和响应压缩。别再用已过时的 WebClient 或手动管理 HttpWebRequest。
关键点:
-
HttpClient应作为单例或静态成员长期持有,不要每次请求都 new —— 否则会耗尽端口、触发SocketException: Too many open files - 务必用
await client.GetAsync(url),避免.Result或.Wait()造成死锁(尤其在 WinForms/WPF 同步上下文中) - 超时需显式设置:
client.Timeout = TimeSpan.FromSeconds(10);,默认是 100 秒,太长
private static readonly HttpClient _client = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
public async Task<string> GetAsync(string url)
{
var response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
HttpRequestMessage + SendAsync 适合带复杂头或重试逻辑
当你需要手动控制请求头(如 Authorization、If-None-Match)、添加自定义中间件行为,或集成 Polly 做重试/熔断时,绕过 GetAsync 便捷方法更灵活。
注意:
-
HttpRequestMessage是一次性对象,不能复用;但HttpClient可复用 - 手动调用
SendAsync后,必须确保response.Dispose()或用using,否则可能泄漏连接(尤其在异常路径下) - 若需设置
Accept或User-Agent,优先用client.DefaultRequestHeaders,而非每次改request.Headers
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data");
request.Headers.Add("X-Client-Version", "2.1.0");
var response = await _client.SendAsync(request);
using (response) // 确保释放
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
用 WebClient 的唯一合理场景:.NET Framework 4.0 或极简脚本
它在 .NET Core/.NET 5+ 中已标记为 Obsolete,且不支持 async/await 原生语法(只有 DownloadStringAsync 这类事件模型),容易写出阻塞线程的代码。
仅当满足以下全部条件才考虑:
- 项目锁定在 .NET Framework 4.0–4.6.1,且无法升级
- 只是写个临时工具、PowerShell 辅助脚本或 LINQPad 小片段
- 不需要并发、超时控制或认证头
否则,强行用它会埋下 WebException: The operation has timed out 或内存泄漏隐患。
别碰 HttpWebRequest —— 除非你要实现 HTTP 协议栈
它是底层封装,暴露太多细节:要手动处理 GetResponseAsync、BeginGetResponse、证书验证回调、编码解析……出错时堆栈往往指向内部状态机,难调试。
常见误用:
- 忘记调用
request.Abort()导致连接卡在Closing状态 - 手动拼接 URL 时未对参数做
Uri.EscapeDataString,导致 400 Bad Request - 在 .NET Core 中试图调用
GetResponse()同步方法,直接抛PlatformNotSupportedException
现代项目里,它存在的意义只剩兼容遗留代码或教学演示协议流程。
真正要注意的不是“有几种方式”,而是哪一种能让你少 debug 连接超时、DNS 解析失败、连接池耗尽这些隐性问题。选 HttpClient 并正确复用,比纠结语法糖重要得多。


















