Лучший опыт

Зачем использовать HttpClientFactory вместо HttpClient в .NET.

Графическое представление потока запросов-ответов с использованием .NET Core и HttpClientFactory. Изображение получено от Henrique Mauri При разработке на платформе .NET понимание того, как делать эффективные, надежные и масштабируемые веб-запросы, имеет решающее значение. Два основных игрока в этой области  —  HttpClient и HttpClientFactory. Хотя оба они служат для отправки HTTP-запросов и получения HTTP-ответов, есть убедительные аргументы в пользу HttpClientFactor
Зачем использовать HttpClientFactory вместо HttpClient в .NET...

Графическое представление потока запросов-ответов с использованием .NET Core и HttpClientFactory. Изображение получено от Henrique Mauri

При разработке на платформе .NET понимание того, как делать эффективные, надежные и масштабируемые веб-запросы, имеет решающее значение. Два основных игрока в этой области  —  HttpClient и HttpClientFactory. Хотя оба они служат для отправки HTTP-запросов и получения HTTP-ответов, есть убедительные аргументы в пользу HttpClientFactory. Цель этой статьи  —  простым языком раскрыть суть обоих вариантов, указать на подводные камни прямого использования HttpClient и объяснить на практических примерах, почему HttpClientFactory является идеальным выбором для молодых разработчиков, стремящихся улучшить навыки работы с .NET.

Поучительная сказка о HttpClient

Давным-давно в стране .NET разработчики использовали HttpClient для выполнения веб-запросов. Все было просто:

var client = new HttpClient();
var response = await client.GetAsync("https://example.com");
var content = await response.Content.ReadAsStringAsync();

Этот фрагмент кода выглядит просто и эффективно. Однако по мере расширения приложений и увеличения количества запросов разработчики начали сталкиваться с загадочными проблемами. Корень этих проблем оказался в неправильном использовании HttpClient.

Подводные камни прямого использования HttpClient

  1. Исчерпание сокетов. Каждый раз, когда создается новый экземпляр HttpClient для запроса, он занимает сокет. Утилизация HttpClient после использования не приводит к немедленному освобождению сокета из-за состояния TIME_WAIT. В сценариях с высокой нагрузкой это может привести к исчерпанию сокетов, что повлияет на способность приложения устанавливать исходящие соединения.
  2. Нерациональное использование ресурсов. Многократное создание и уничтожение экземпляров HttpClient требует больших ресурсов. Это может привести к ненужным накладным расходам и снижению производительности.
  3. Несогласованная конфигурация. Управление несколькими экземплярами HttpClient может привести к несогласованной конфигурации запросов, что затруднит реализацию глобальных политик, таких как таймауты, заголовки и обработка ошибок.

Героическое появление HttpClientFactory

Для решения этих проблем в .NET появился HttpClientFactory  —  герой, рожденный для эффективного управления экземплярами HttpClient. HttpClientFactory обладает рядом преимуществ, которые делают его идеальным выбором для веб-запросов.

  1. Эффективное управление ресурсами. HttpClientFactory поддерживает пул экземпляров HttpClient. Когда экземпляр больше не нужен, он возвращается в пул для повторного использования, что позволяет снизить уровень исчерпания сокетов и растрату ресурсов.
  2. Согласованная конфигурация. HttpClientFactory позволяет централизованно конфигурировать экземпляры HttpClient. Таким образом, обеспечивается согласованность всех HTTP-запросов с точки зрения заголовков, таймаутов и других политик.
  3. Высокая отказоустойчивость и политики Polly. Интеграция с Polly, библиотекой с возможностями обработки временных сбоев и обеспечения отказоустойчивости, стала проще благодаря HttpClientFactory. Это позволяет разработчикам легко реализовать политики повторных запросов, остановки запросов и многое другое, повышая надежность HTTP-запросов.

Полезное приключение с участием HttpClientFactory

Чтобы увидеть HttpClientFactory в действии, стоит поработать с кодом. Прежде всего зарегистрируйте HttpClientFactory при запуске приложения:

// Прежде всего, убедитесь, что вы установили необходимые пакеты Polly NuGet:: // Microsoft.Extensions.Http.Polly // Polly  var retryPolicy = HttpPolicyExtensions.HandleTransientHttpError() // Обработка ошибок HTTP 5xx или запросов HTTP 408 .WaitAndRetryAsync( retryCount: 3, // Повторите попытку три раза sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)), // Экспоненциальная выдержка: 2, 4, 8 секунд onRetry: (outcome, timespan, retryAttempt, context) => { // Это действие, которое нужно предпринять при каждой повторной попытке: записать в журнал или предпринять другое действие. Console.WriteLine($"Retrying due to: {outcome.Exception?.Message}. Wait time: {timespan}. Attempt: {retryAttempt}."); });  // Регистрация HttpClientFactory в интеграции Polly builder.Services.AddHttpClient("ExampleClient", client => { // Здесь можно применить согласованные конфигурации ко всем HttpClient'ам client.BaseAddress = new Uri("https://example.com"); client.DefaultRequestHeaders.Add("Accept", "application/json"); client.Timeout = TimeSpan.FromSeconds(30); // Установите глобальный таймаут для запросов }) .AddPolicyHandler(retryPolicy); // Используйте политику Polly  Теперь внедрите IHttpClientFactory в сервис или контроллер:public class MyService { private readonly IHttpClientFactory _clientFactory;  public MyService(IHttpClientFactory clientFactory) { _clientFactory = clientFactory; }  public async Task<string> GetWebContentAsync(string url) { var client = _clientFactory.CreateClient("ExampleClient"); var response = await client.GetAsync(url); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); return content; } }

В этом примере сначала определяем политику повторных попыток с помощью Polly. Согласно этой политике, любой запрос, столкнувшийся с временной ошибкой, будет повторен до трех раз с экспоненциальной выдержкой. Затем регистрируем HttpClient в HttpClientFactory и связываем с ним политику повторных попыток. Теперь все HTTP-клиенты, созданные с именем “ExampleClient”, будут использовать эту политику и указанную конфигурацию, обеспечивая согласованность во всем приложении.

Преимущества, которые обеспечивает этот паттерн:

  • Отказоустойчивость. Приложение становится более устойчивым к внешним воздействиям за счет изящной обработки временных сбоев.
  • Согласованная конфигурация. Все экземпляры HttpClient, созданные с помощью factory, будут иметь одинаковый базовый адрес, заголовки и настройки таймаута, что обеспечивает согласованность.
  • Эффективное управление ресурсами. HttpClientFactory управляет базовыми обработчиками HttpClient для оптимизации пула соединений и жизненного цикла.

Интеграция с Polly не только делает HTTP-вызовы более надежными, но и упрощает управление конфигурациями HttpClient и применение политики отказоустойчивости во всех приложениях .NET.

Поучительный вывод

Для начинающих разработчиков .NET, осваивающих сферу веб-запросов, HttpClientFactory  —  не просто инструмент. Это путеводитель по написанию более эффективных, масштабируемых и устойчивых приложений. Он указывает на важность управления ресурсами, опасность исчерпания сокетов, преимущества согласованной конфигурации и паттернов отказоустойчивости.

Выбирая HttpClientFactory вместо прямого использования HttpClient, вы не просто избегаете потенциальных ловушек. Вы следуете лучшим практикам, становясь продвинутым разработчиком .NET. Поэтому, когда в очередной раз будете выполнять HTTP-запросы в приложении .NET, вспомните о HttpClientFactory и о множестве преимуществ, которые он привносит в ваш инструментарий разработчика.