HttpClientFactory-向外請求的最佳
- 2020 年 6 月 7 日
- 筆記
- .NET, .NET Core
簡介
- 它的組件包是Microsoft.Extensions.Http
- 復原HttpClient帶來的問題
HttpClient相關問題
- 雖然HttpClient類實現了IDisposable,但不是首選在using語句中聲明和實例化它,因為釋放HttpClient對象時,基礎套接字不會立即釋放,這可能會導致「套接字耗盡」問題 。因此,HttpClient 應進行一次實例化並在應用程式的生命周期中重複使用。 在負載較重的情況下,實例化每個請求的 HttpClient 類將耗盡可用的套接字數。 該問題會導致 SocketException 錯誤。 要解決此問題,可能的方法是將 HttpClient 對象創建為單一對象或靜態對象,在長期運行的進程中使用 HttpClient 的共享實例時,開發人員遇到的另一個問題。 在將 HttpClient 實例化為單一實例或靜態對象的情況下,它無法處理 DNS 更改,但是,問題實際上不是 HttpClient 本身,而是 HttpClient 的默認構造函數,因為它創建了一個新的實際 HttpMessageHandler 實例,該實例具有上面提到的「套接字耗盡」和 DNS 更改問題 。
參考解決內容
核心點
- 管理內部HttpMessageHandler的生命周期,靈活應對資源問題和DNS刷新問題。
- 支援命名化,類型化配置,集中管理配置,避免衝突
- 靈活的出站請求管道配置,輕鬆管理請求生命周期
- 內置管道最外層和最記憶體日誌記錄器,有Information和Trace輸出
核心對象
- HttpClient
- HttpMessageHandler
- SocketsHttpHandler
- DelegatingHandler
- IHttpClientFactory
- IHttpClientBuilder
使用方式
- 基本用法
- 命名客戶端模式
- 類型化客戶端模式
- 生成的客戶端
基本用法
//首先,在Startup中的ConfigureService註冊我們的HttClient服務,僅僅一行程式碼就可以搞定
service.AddHttpClien();
//接著,我們通過依賴注入來請求IHttpClientFactory,並創建HttpClient實例,以下程式碼之後我們就可以放心使用HttpClient
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var client = _clientFactory.CreateClient();
}
類型化客戶端
publi class XXXClient
{
IHttpClientFactory _httpclientFatory;
public XXXClient(IHttpClientFactory httpclientFatory)
{
_httpclientFatory=httpclientFatory;
}
public async Task<string> Get()
{
var client = _httpclientFatory.CreateClient();
return await client.GetStringAsync("xxx.url");
}
}
註冊
services.AddHttpClient<XXXClient>();
出站請求中間件
創建委託處理程式
- 派生自DelegatingHandler (將 HTTP 響應消息的處理委託給另一處理程式(稱為「內部處理程式」)的 HTTP 處理程式的類型。)
- 重寫SendAsync
程式碼
public class xxxHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//處理請求
var result = await base.SendAsync(request, cancellationToken); //調用內部handler
//處理響應
return result;
}
}
public void ConfigureServices(IServiceCollection services){
services.AddSingleton<xxxHandler>();
services.AddHttpClient("XXXServiceClient", client =>
{
client.DefaultRequestHeaders.Add("client-name", "namedclient");
client.BaseAddress = new Uri("//localhost:5003");
}).SetHandlerLifetime(TimeSpan.FromMinutes(20))
.AddHttpMessageHandler(provider => provider.GetService<xxxHandler>());
services.AddScoped<xxxHandler>();
}
public class XXXServiceClient
{
IHttpClientFactory _httpClientFactory;
const string _clientName = "NamedOrderServiceClient"; //定義客戶端名稱
public XXXServiceClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<string> Get()
{
var client = _httpClientFactory.CreateClient(_clientName); //使用客戶端名稱獲取客戶端
//使用client發起HTTP請求,這裡使用相對路徑來訪問
return await client.GetStringAsync("/OrderService");
}
}
生命周期
- 每次對 IHttpClientFactory 調用 CreateClient 都會返回一個新 HttpClient 實例。 每個命名客戶端都創建一個 HttpMessageHandler。 工廠管理 HttpMessageHandler 實例的生存期。
- 處理程式的默認生存期為兩分鐘,可通過SetHandlerLifetime 重新設置。