介绍 HttpClientFactory
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
几年前,我偶然看到一篇 ASP.NET Monsters 的博客文章,标题是:《你错误地使用了 HttpClient,它正在破坏你的软件稳定性》。这篇文章分享了一个技巧,我曾多次使用过,那就是通过不释放 HttpClient 来避免套接字耗尽。
处置还是不处置,这是个问题。
创建 HttpClient 实例时,内部会创建一个 HttpMessageHandler 链。正是这个处理程序链负责建立连接。
因此,当我们释放 HttpClient 时,实际上也释放了 HttpMessageHandler,最终会导致连接关闭。
这样做的风险在于,客户端被释放后,连接并不会立即关闭。
当我们主动关闭连接时,端口不会立即释放,而是会进入 TIME_WAIT 状态。
如果这种情况持续发生,最终会导致套接字耗尽。
上述问题的一种解决方案是使用一个可供整个应用程序共享的 HttpClient 实例。但
这种方案的问题在于,连接会一直保持打开状态并被重复使用,远程服务上的任何 DNS 更改都不会生效。
这会导致应用程序指向离线的服务器实例或错误的运行环境。
介绍 HttpClientFactory
- HttpClientFactory 是在 .NETCore 2.1 中引入的。
- HttpClientFactory 为我们提供了一个集中配置和创建 HttpClient 的地方。
- 它管理底层 HttpMessageHandler 链的生命周期。它通过管理一个 MessageHandler 池并保持这些 MessageHandler 处于打开状态直至过期来实现这一点。
- MessageHandlers 最多保持存活 2 分钟(默认情况下)。
- 这样我们就能兼顾两者的优点,既能保持连接足够长的时间,又能响应 DNS 的更改。
使用 HttpClientFactory 的模式
直接使用
- 使用 HttpClientFactory 非常简单,只需要对应用程序进行极少的代码更改。
- 如果您的应用程序未引用 Microsoft.AspNetCore.App 元包,请安装 Microsoft.Extensions.Http NuGet 包。
- 只需调用 IServiceCollection 上的 AddHttpClient 扩展方法,即可获得开箱即用的实例管理功能。
- 它允许您将 HttpClientFactory 注入到应用程序中的任何位置,您可以使用它来创建 HttpClient 实例。
指定客户
- 命名客户端使我们能够为应用程序与之通信的不同服务创建逻辑配置。
- 配置命名客户端非常简单,只需调用 AddHttpClient 方法,传入客户端名称和一个接受 HttpClient 的委托即可。
- 要访问已命名的 HttpClient,只需将已配置客户端的名称传递给 IHttpClientFactory 上的 CreateClient 方法即可。
类型化客户
- 类型化客户端是(微软推荐的)使用 HttpClient 的方式。
- 类型化客户端只是一个接受 HttpClient 作为构造函数参数的类。
- 类型化客户端的优势在于可以将特定于服务的代码封装到一个类中。
奖金
您可能已经注意到 GetMorty 操作中使用的 FromServices 属性,并问自己:这是什么鬼!
- FromServices 属性从容器中获取 action 参数。
- 这发生在 MVC 请求生命周期的 ModelBinding 阶段,此时 ControllerActionInvoker 会根据请求在控制器中找到匹配的操作。
- 在调用操作之前,该类型的一个实例会绑定到操作的参数上。
结语
- 使用 HttpClientFactory 可以提高 HTTP 调用的稳定性。
- 在配置 HttpClient 时,可以通过将 SetLifeTime 方法链接到 AddClient 方法来覆盖默认的 HttpMessageHandler 生命周期。
- 按照建议,尽可能使用类型化客户端。
- 点击此处访问示例源代码








