ASP.NET Core 的出站请求客户端
参考资料:
本文索引:
前言
当应用有对外部 Http 服务有依赖时,通常的做法是在应用内部使用 HttpClient
。ASP.NET Core 加入了 HttpClientFactory
,以集中的方式管理 HttpClient
及其使用的系统资源。
用法
这些用法分别对应于 services.AddHttpClient()
方法的几个重载,并且适用于不同的场景:
- 基本用法:
services.AddHttpClient()
- 命名
HttpClient
:services.AddHttpClient(string name, Action<HttpClient> configureClient)
- 强类型
HttpClient
: 不再以string
类型参数提供key
,而是以单独的服务类型通过依赖注入的方式提供HttpClient
实例,services.AddHttpClient<TService>
- 动态
HttpClient
配置 HttpMessageHandler
在 services.AddHttpClient
方法重载中,有一些返回 IHttpClientBuilder
实例,该实例可用于进一步对该客户端进行配置:
1 | services.AddHttpClient("configured-inner-handler").ConfigurePrimaryHttpMessageHandler(() => |
可借由此功能定制出站请求的 HttpMessageHandler
或使用 Mock 的处理程序以支持测试。
出站请求中间件
HttpClient
本身其实是将出站请求交给相应的委托进行处理,可以传入继承自 HttpMessageHandler
类型的实例来创建 HttpClient
实例。IHttpClientFactory
简化了为不同命名 HttpClient
注入预期的 HttpMessageHandler
。可通过继承 DelegatingHandler
类型并重写 SendAsync
方法来实现 Handler
的处理逻辑:
1 | public class MyCustomHandler : DelegatingHandler |
这样,在添加 AddHttpClient
服务时可对其配置相应的 Handler
:
1 | services.AddTransient<MyCustomHandler>(); |
值得注意的是,
MyCustomHandler
必须在 DI 中以瞬时(Transient)生存期注册
可为同一个 IHttpClientFactory
多次调用 AddHttpMessageHandler
方法,Handler
将按照注册的顺序依次执行,这样将形成 Handler
链,一个 Handler
将包装下一个 Handler
。与 ASP.NET Core 管道的概念类似,例如:
1 | services.AddTransient<SecureRequestHandler>(); |
基于 Polly 的 Handlers
IHttpClientFactory
通过扩展方法支持与 Polly 的 Policy
集成。这些扩展方法定义在 Microsoft.Extensions.Http.Polly
包中。
例如,用于从临时故障中重试的 AddTransientHttpErrorPolicy
,定义了请求失败后最多重试三次,每次尝试间隔 600 ms 的 Policy
:
1 | services.AddHttpClient<UnreliableEndpointCallerService>().AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600))); |
其他一些扩展方法用于支持 Polly-based 处理程序,例如 AddPolicyHandler()
方法:
1 | var timeout = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)); |
上述代码中,如果出站请求为 GET,则应用 10 秒超时。其他所有 HTTP 方法应用 30 秒超时。
嵌套 Polly 策略以增强功能是很常见的:
1 | services.AddHttpClient("multiplepolicies") |
上述示例中,添加了两个 Handler。 第一个使用 AddTransientHttpErrorPolicy
扩展添加重试策略。若请求失败,最多重试三次。第二个调用 AddTransientHttpErrorPolicy
添加断路器策略。如果尝试连续失败了五次,则会阻止后续外部请求 30 秒,并且通过此 HttpClientFactory
进行的所有调用都共享同样的线路状态。
HttpClient 的生存期
每次调用 IHttpClientFactory.CreateClient
都会返回一个新的 HttpClient
实例。一个命名 HttpClient
服务关联一个 HttpMessageHandler
实例。IHttpClientFactory
将这些 HttpMessageHandler
实例汇集到池中,以减少资源消耗。
日志记录
由 IHttpClientFactory
创建的客户端包含了请求的所有日志消息。单个客户端的管道外部以 LogicalHandler
类别来记录消息,而管道内部以 ClientHandler
类别记录。