在 HttpClientFactory 出生之前,由於 HttpClient 臭名昭著的“dispose之后4分鍾TCP連接才會被關閉”問題(詳情),只能使用單例或靜態的 HttpClient ,比如
private static readonly HttpClient _httpClient = new HttpClient() { BaseAddress = new Uri("www.cnblogs.com") };
但這會帶來一個副作用,如果 dns 解析更新了,HttpClient 不會自動更新IP地址。我們就被這個問題坑過,當時一個 web api 的 IP 地址變更了,不得不重啟所有調用這個 web api 的應用。
隨着 .NET Core 2.1 的發布,HttpClientFactory 橫空出世,有效地解決了 HttpClient 的生命周期與對應的TCP連接管理的問題。
今天實際體驗了一下,將一個項目中使用靜態 HttpClient 的地方改為使用 HttpClientFactory 。
由於所在項目的 target framework 是 netstandard 2.0,所以需要安裝包含 HttpClientFactory 的 nuget 包 Microsoft.Extensions.Http (如果是引用了 Microsoft.AspNetCore.App 的 netcoreapp2.1 項目,則不需要安裝)。
首先,將之前定義靜態 HttpClient 的地方改為通過構造函數依賴注入:
public class UCenterService : IUCenterService { private ILogger _logger; private readonly HttpClient _httpClient; public UCenterService(ILoggerFactory loggerFactory, HttpClient httpClient) { _logger = loggerFactory.CreateLogger<UCenterService>(); _httpClient = httpClient; } }
然后在 Startup 的 ConfigureServices 中通過 HttpClientFactory 提供的擴展方法進行注冊(這里用的是 typed client 方式):
services.AddHttpClient<IUCenterService, UCenterService>(c => { c.BaseAddress = new Uri("http://www.cnblogs.com"); });
通過這兩步操作后就輕松搞定 HttpClientFactory 的運用,並在實際項目中驗證通過。
看看上面的注冊代碼,感覺好強大,可以在注冊時根據類型(UCenterService)配置對應的 HttpClient 實例。
除此之外,在注冊時還可以設置 HttpMessageHandler 實例被重用(也就是TCP連接重用)的生命周期(默認是2分鍾),正是 HttpMessageHandler 實例被定期釋放解決了 dns 解析更新的問題。
services.AddHttpClient<IUCenterService, UCenterService>(c => { c.BaseAddress = new Uri("http://www.cnblogs.com"); }) .SetHandlerLifetime(TimeSpan.FromMinutes(5));
而且集成了 Polly ,可以配置策略對瞬時故障進行處理(需要安裝 nuget 包 Microsoft.Extensions.Http.Polly )
services.AddHttpClient<IUCenterService, UCenterService>(c => { c.BaseAddress = new Uri("http://www.cnblogs.com"); }) .SetHandlerLifetime(TimeSpan.FromMinutes(5)) .AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(500)));
還有強大的 outgoing request middleware pipeline ,目前還沒用到,留待以后體驗。
參考資料:
1)HttpClientFactory in ASP.NET Core 2.1 (Part 1) An Introduction to HttpClientFactory
2)HttpClientFactory in ASP.NET Core 2.1 (Part 2) Defining Named and Typed Clients
3)HttpClientFactory in ASP.NET Core 2.1 (Part 3) Outgoing request middleware with handlers
4)HttpClientFactory in ASP.NET Core 2.1 (Part 4) Integrating with Polly for transient fault handling