在 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