HttpClientFactory 使用 SocketsHttpHandler 作为主处理程序
HttpClientFactory
允许为命名对象和类型化HttpClient对象配置HttpMessageHandler管道。 最内部的处理程序或实际在网络上发送请求的处理程序称为 主处理程序。 如果未配置,则此处理程序以前始终是一个 HttpClientHandler。 虽然默认的主处理程序是实现详细信息,但有用户依赖于它。 例如,某些用户将主处理程序强制转换为 HttpClientHandler
设置属性,例如 ClientCertificates, UseCookies和 UseProxy。
通过此更改,默认的主处理程序是 SocketsHttpHandler 支持它的平台。 在其他平台上(例如,.NET Framework) HttpClientHandler 将继续使用。
SocketsHttpHandler
现在还具有 PooledConnectionLifetime 与值匹配 HandlerLifetime 的属性预设。 (它反映用户配置的最新值 HandlerLifetime
)。
引入的版本
.NET 9 预览版 6
旧行为
默认的主处理程序为 HttpClientHandler
. 将其强制转换为 HttpClientHandler
更新属性的操作。
services.AddHttpClient("test")
.ConfigurePrimaryHttpMessageHandler((h, _) =>
{
((HttpClientHandler)h).UseCookies = false;
});
// This worked.
var client = httpClientFactory.CreateClient("test");
新行为
在支持的平台 SocketsHttpHandler
上,默认的主处理程序现在 SocketsHttpHandler
已 PooledConnectionLifetime
设置为 HandlerLifetime
值。 将其强制转换为 HttpClientHandler
更新属性会引发一个 InvalidCastException。
例如,“上一行为”部分中的相同代码现在引发以下代码InvalidCastException:
System.InvalidCastException:无法将类型为“System.Net.Http.SocketsHttpHandler”的对象强制转换为“System.Net.Http.HttpClientHandler”。
中断性变更的类型
此更改为行为更改。
更改原因
用户遇到的最常见问题HttpClientFactory
之一是,在Named
Typed
单一实例服务中错误地捕获客户端,或者通常,存储在某个时间长于指定HandlerLifetime时间的某个时间。 由于 HttpClientFactory
无法轮换此类处理程序,因此它们最终可能不尊重 DNS 更改。
可以使用 SocketsHttpHandler此选项来控制 PooledConnectionLifetime此问题。 同样 HandlerLifetime,共用连接生存期允许定期重新创建连接来选取 DNS 更改,但在较低级别。 具有设置的 PooledConnectionLifetime
客户端可以安全地用作单一实例。
不幸的是,将客户端注入 Typed
单一实例很容易且看似“直观”。 但是,很难进行任何类型的检查或分析器,以确保 HttpClient
在不应捕获时未捕获。 此外,很难排查生成的问题。 因此,作为预防性措施,为了最大程度地减少错误使用模式的潜在影响, SocketsHttpHandler
缓解措施现在默认应用。
此更改仅影响最终用户未将客户端配置为使用自定义 PrimaryHandler (例如,通过) ConfigurePrimaryHttpMessageHandler<THandler>(IHttpClientBuilder)的情况。
建议的操作
有三个选项可用于解决重大更改:
为每个客户端显式指定和配置主处理程序:
services.AddHttpClient("test") .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false });
使用 ConfigureHttpClientDefaults(IServiceCollection, Action<IHttpClientBuilder>): 覆盖所有客户端的默认主处理程序:
services.ConfigureHttpClientDefaults(b => b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }));
在配置操作中,检查两者以及
HttpClientHandler
SocketsHttpHandler
:services.AddHttpClient("test") .ConfigurePrimaryHttpMessageHandler((h, _) => { if (h is HttpClientHandler hch) { hch.UseCookies = false; } if (h is SocketsHttpHandler shh) { shh.UseCookies = false; } });