Поделиться через


HttpClientFactory использует SocketsHttpHandler в качестве основного обработчика

HttpClientFactory позволяет настроить HttpMessageHandler конвейер для именованных и типизированных HttpClient объектов. Внутренний обработчик или тот, который фактически отправляет запрос по проводу, называется основным обработчиком. Если этот обработчик не настроен, этот обработчик всегда 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;
          }
      });
    

Затронутые API