HttpClientFactory 使用 SocketsHttpHandler 作为主处理程序

HttpClientFactory允许为命名对象和类型化HttpClient对象配置HttpMessageHandler管道。 最内部的处理程序或实际在网络上发送请求的处理程序称为 主处理程序。 如果未配置,则此处理程序以前始终是一个 HttpClientHandler。 虽然默认的主处理程序是实现详细信息,但有用户依赖于它。 例如,某些用户将主处理程序强制转换为 HttpClientHandler 设置属性,例如 ClientCertificatesUseCookiesUseProxy

通过此更改,默认的主处理程序是 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 上,默认的主处理程序现在 SocketsHttpHandlerPooledConnectionLifetime 设置为 HandlerLifetime 值。 将其强制转换为 HttpClientHandler 更新属性会引发一个 InvalidCastException

例如,“上一行为”部分中的相同代码现在引发以下代码InvalidCastException

System.InvalidCastException:无法将类型为“System.Net.Http.SocketsHttpHandler”的对象强制转换为“System.Net.Http.HttpClientHandler”。

中断性变更的类型

此更改为行为更改

更改原因

用户遇到的最常见问题HttpClientFactory之一是,在NamedTyped单一实例服务中错误地捕获客户端,或者通常,存储在某个时间长于指定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 }));
    
  • 在配置操作中,检查两者以及HttpClientHandlerSocketsHttpHandler

    services.AddHttpClient("test")
      .ConfigurePrimaryHttpMessageHandler((h, _) =>
      {
          if (h is HttpClientHandler hch)
          {
              hch.UseCookies = false;
          }
    
          if (h is SocketsHttpHandler shh)
          {
              shh.UseCookies = false;
          }
      });
    

受影响的 API