Рекомендации по использованию HttpClient

Класс System.Net.Http.HttpClient отправляет HTTP-запросы и получает http-ответы от ресурса, определяемого URI. Экземпляр HttpClient представляет собой коллекцию параметров, применяемых ко всем запросам, выполняемым этим экземпляром, и каждый экземпляр использует собственный пул подключений, который изолирует свои запросы от других. Начиная с .NET Core 2.1, SocketsHttpHandler класс предоставляет реализацию, обеспечивая согласованность поведения на всех платформах.

Поведение DNS

HttpClient разрешает только записи DNS при создании подключения. Он не отслеживает срок жизни (TTL), указанный DNS-сервером. Если записи DNS регулярно изменяются, что может произойти в некоторых сценариях, клиент не будет уважать эти обновления. Чтобы устранить эту проблему, можно ограничить время существования подключения, задав PooledConnectionLifetime свойство, чтобы поиск DNS повторялся при замене подключения. Рассмотрим следующий пример:

var handler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(15) // Recreate every 15 minutes
};
var sharedClient = new HttpClient(handler);

Предыдущий HttpClient параметр настраивается для повторного использования подключений в течение 15 минут. После истечения интервала времени, указанного PooledConnectionLifetime в истечении времени, соединение закрывается и создается новое.

Подключения в пуле

Пул соединений для объекта HttpClient связан с базовым SocketsHttpHandler. HttpClient При удалении экземпляра все существующие подключения в пуле удаляются. Если вы позже отправите запрос на тот же сервер, необходимо повторно создать новое подключение. В результате возникает штраф за производительность для создания ненужных подключений. Кроме того, TCP-порты не выпускаются сразу после закрытия подключения. (Дополнительные сведения об этом см. в статье TCP TIME-WAIT в RFC 9293.) Если скорость запросов высока, ограничение операционной системы доступных портов может быть исчерпано. Чтобы избежать проблем с исчерпанием портов, рекомендуется повторно использовать HttpClient экземпляры для максимально возможного количества HTTP-запросов.

Чтобы суммировать рекомендуемое HttpClient использование с точки зрения управления временем существования, следует использовать либо долгосрочные клиенты, либо задать PooledConnectionLifetime (.NET Core и .NET 5+) или краткосрочные клиенты, созданные IHttpClientFactory.

  • В .NET Core и .NET 5+:

    • static Используйте экземпляр или одноэлементныйHttpClient экземпляр с PooledConnectionLifetime заданным интервалом, например 2 минуты, в зависимости от ожидаемых изменений DNS. Это позволяет решить проблемы нехватки портов и DNS без добавления дополнительных IHttpClientFactoryзатрат. Если вы должны иметь возможность макетировать обработчик, его можно зарегистрировать отдельно.

    Совет

    Если вы используете только ограниченное количество HttpClient экземпляров, это также допустимая стратегия. Важно, что они не создаются и удаляются с каждым запросом, так как они содержат пул подключений. Использование нескольких экземпляров необходимо для сценариев с несколькими прокси-серверами или для разделения контейнеров cookie без полной отключения обработки файлов cookie.

    • С помощью IHttpClientFactoryможно использовать несколько разных клиентов, настроенных для разных вариантов использования. Тем не менее, помните, что созданные фабрикой клиенты предназначены для кратковременного существования, и после создания клиента фабрика больше не имеет контроля над ним.

      Экземпляры пулов фабрики HttpMessageHandler и, если срок его существования не истек, обработчик можно повторно использовать из пула при создании нового HttpClient экземпляра. Это повторное использование позволяет избежать проблем с исчерпанием сокета.

      Если требуется настройка, которая IHttpClientFactory предоставляется, рекомендуется использовать подход с типизированным клиентом.

  • В платформа .NET Framework используйте IHttpClientFactory для управления HttpClient экземплярами. Если вы не используете фабрику и вместо этого создаете новый экземпляр клиента для каждого запроса самостоятельно, вы можете исчерпать доступные порты.

    Совет

    Если приложению требуются файлы cookie, рекомендуется отключить автоматическую обработку файлов cookie или избежать IHttpClientFactory. HttpMessageHandler Объединение экземпляров приводит к совместному CookieContainer использованию объектов. Непредвиденное совместное использование объектов CookieContainer часто приводит к ошибкам в коде.

Дополнительные сведения об управлении HttpClient временем существования смIHttpClientFactoryIHttpClientFactory. в рекомендациях.

Устойчивость со статическими клиентами

Можно настроить static или одиночный клиент для использования любого количества конвейеров устойчивости с помощью следующего шаблона:

using System;
using System.Net.Http;
using Microsoft.Extensions.Http;
using Microsoft.Extensions.Http.Resilience;
using Polly;

var retryPipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
    .AddRetry(new HttpRetryStrategyOptions
    {
        BackoffType = DelayBackoffType.Exponential,
        MaxRetryAttempts = 3
    })
    .Build();

var socketHandler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(15)
};
var resilienceHandler = new ResilienceHandler(retryPipeline)
{
    InnerHandler = socketHandler,
};

var httpClient = new HttpClient(resilienceHandler);

Предыдущий код:

  • Использует пакет NuGet Microsoft.Extensions.Http.Resilience.
  • Задает временный обработчик ошибок HTTP, настроенный с конвейером повторных попыток, который при каждой попытке будет экспоненциально выполнять интервалы задержки.
  • Определяет время существования подключения в пуле в течение пятнадцати минут socketHandler.
  • Передается socketHandlerresilienceHandler в логику повторных попыток.
  • Создает экземпляр заданного HttpClientresilienceHandlerобъекта .

Внимание

Библиотека Microsoft.Extensions.Http.Resilience в настоящее время помечена как экспериментальная , и она может измениться в будущем.

См. также