簡介
HttpClient
是 .NET
中用于發送 HTTP
請求和接收 HTTP
響應的現代化 API
,它取代了過時的 WebClient
和 HttpWebRequest
類。
HttpClient
是 .NET Framework 4.5
+ 和 .NET Core/.NET 5+
中提供的、基于消息處理管道(message handler pipeline
)的現代 HTTP
客戶端庫。
相比早期的 HttpWebRequest
,它更易用、支持異步、可擴展性強,并且在 .NET Core
中底層使用 SocketsHttpHandler
,性能與可配置性都有顯著提升。
底層架構
-
HttpClient
- 封裝請求創建、發送及響應處理邏輯,提供
GetAsync、PostAsync、SendAsync
等方法。
- 封裝請求創建、發送及響應處理邏輯,提供
-
HttpMessageHandler
管道-
默認使用
SocketsHttpHandler(.NET Core/.NET 5+)
,.NET Framework
下為HttpClientHandler
。 -
可以通過繼承
DelegatingHandler
串聯多個自定義中間件(例如日志、重試、認證)。
-
-
連接池與長連接
SocketsHttpHandler
內置連接池和HTTP/2
支持,同一目標主機復用TCP
連接,減少握手與重建成本。
HttpClient 核心特性
特性 | 說明 | 優勢 |
---|---|---|
異步支持 | 所有方法都有異步版本 | 避免阻塞線程,提高并發能力 |
連接池 | 自動管理 HTTP 連接 | 減少 TCP 連接開銷 |
超時控制 | 可配置請求超時時間 | 防止長時間阻塞 |
內容處理 | 內置多種內容處理器 | 簡化 JSON/XML 處理 |
取消支持 | 支持 CancellationToken | 優雅終止長時間請求 |
擴展性 | 可通過 DelegatingHandler 擴展 | 實現日志、重試等中間件 |
常用方法
使用單例
public static class HttpClientSingleton
{public static readonly HttpClient Instance = new HttpClient();
}// 使用
await HttpClientSingleton.Instance.GetAsync(url);
-
全局唯一,避免重復創建
handler
,復用連接池。 -
需注意:設置到期(
Timeout
)、默認頭(DefaultRequestHeaders
)等全局屬性變更會影響所有調用。
使用 HttpClientFactory
工廠
services.AddHttpClient("GitHub", client =>
{client.BaseAddress = new Uri("https://api.github.com/");client.DefaultRequestHeaders.Add("User-Agent", "MyApp");
})
.AddTransientHttpErrorPolicy(policy =>policy.WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(2)));// 使用
var client = _httpClientFactory.CreateClient("GitHub");
-
框架管理生命周期、穩定重用
SocketsHttpHandler
。 -
支持命名客戶端、類型化客戶端、配置管道、添加
Polly
彈性策略。
類型化客戶端
public class GitHubService {private readonly HttpClient _client;public GitHubService(HttpClient client) => _client = client;// 封裝API方法
}
// 注冊
services.AddHttpClient<GitHubService>(client => { /* 配置 */ });
GET
請求
var client = HttpClientSingleton.Instance;
var response = await client.GetAsync("https://api.example.com/items/1");
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
POST
請求
var content = new StringContent(JsonSerializer.Serialize(new { Name = "測試" }),Encoding.UTF8, "application/json");
var postResp = await client.PostAsync("https://api.example.com/items", content);
postResp.EnsureSuccessStatusCode();
SendAsync
自定義請求
var request = new HttpRequestMessage(HttpMethod.Put, $"items/{id}")
{Content = new StringContent(json, Encoding.UTF8, "application/json")
};
request.Headers.Add("X-Custom", "Value");using var resp = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
resp.EnsureSuccessStatusCode();
流式上傳/下載
// 下載
using var resp = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead);
using var stream = await resp.Content.ReadAsStreamAsync();
// 將 stream 寫入文件 ...// 上傳
using var fs = File.OpenRead(localFilePath);
var streamContent = new StreamContent(fs);
var uploadResp = await client.PostAsync(uploadUrl, streamContent);
DelegatingHandler 管道
public class LoggingHandler : DelegatingHandler
{protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct){Console.WriteLine($"Request: {request}");var resp = await base.SendAsync(request, ct);Console.WriteLine($"Response: {resp}");return resp;}
}// 注冊(HttpClientFactory)
services.AddHttpClient("WithLogging").AddHttpMessageHandler<LoggingHandler>();
Polly 彈性策略
services.AddHttpClient("GitHub").AddTransientHttpErrorPolicy(p =>p.WaitAndRetryAsync(3, retry => TimeSpan.FromSeconds(1)));
-
AddTransientHttpErrorPolicy
捕獲5xx、408、HttpRequestException
等transient
錯誤; -
可組合斷路器、超時、隔離策略。
認證與配置
Bearer Token
client.DefaultRequestHeaders.Authorization =new AuthenticationHeaderValue("Bearer", accessToken);
Client Certificates
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(new X509Certificate2("cert.pfx", "pwd"));
var client = new HttpClient(handler);
代理
handler.Proxy = new WebProxy("http://127.0.0.1:8888");
handler.UseProxy = true;
設置超時和請求頭
httpClient.Timeout = TimeSpan.FromSeconds(30); // 設置全局超時
httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "your-token");
處理不同類型的響應
// 獲取 JSON 響應
var jsonResponse = await httpClient.GetStringAsync("https://api.example.com/json");// 獲取二進制響應(如文件下載)
var bytes = await httpClient.GetByteArrayAsync("https://example.com/file.pdf");// 獲取流響應(大文件下載,避免內存溢出)
await using var stream = await httpClient.GetStreamAsync("https://example.com/largefile.zip");await using var fileStream = File.Create("largefile.zip");
await stream.CopyToAsync(fileStream);
發送帶參數的請求
// GET 請求帶查詢參數
var queryParams = new Dictionary<string, string>
{{ "page", "1" },{ "size", "20" }
};
var uri = new UriBuilder("https://api.example.com/data")
{Query = new FormUrlEncodedContent(queryParams).ReadAsStringAsync().Result
};
var response = await httpClient.GetAsync(uri.Uri);// POST 請求帶表單數據
var formContent = new FormUrlEncodedContent(new[]
{new KeyValuePair<string, string>("username", "test"),new KeyValuePair<string, string>("password", "pass")
});
await httpClient.PostAsync("https://example.com/login", formContent);
處理 HTTP 錯誤
try
{var response = await httpClient.GetAsync("https://api.example.com/resource");response.EnsureSuccessStatusCode(); // 非 200 狀態碼會拋出異常
}
catch (HttpRequestException ex)
{Console.WriteLine($"HTTP Error: {ex.StatusCode}");Console.WriteLine($"Message: {ex.Message}");
}
處理 gzip/deflate 壓縮響應
var httpClientHandler = new HttpClientHandler
{AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var httpClient = new HttpClient(httpClientHandler);
取消操作
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); // 10秒超時
try {var response = await client.GetAsync("https://slow-api.com", cts.Token);
} catch (TaskCanceledException) {// 處理超時
}