Перейти к содержанию

Использование IHttpClientFactory для управления жизненным циклом HttpClientHandler

Начнём с того, что класс HttpClient отвечает за оркестровку запросов, но не за само соединение. Вместо этого он вызывает конвейер HttpMessageHandler, в конце которого находится HttpClientHandler, который устанавливает фактическое соединение и отправляет HTTP-запрос, как показано на картинке.
Pasted image 20221019210103.png
Эта конфигурация напоминает конвейер промежуточного ПО, хоть это и исходящий конвейер. Каждый обработчик может изменить запрос до того, как последний HttpClientHandler выполнит настоящий запрос, а также получает возможность посмотреть ответ после получения.
Проблемы исчерпания сокетов и ротации DNS связаны с удалением HttpClientHandler в конце конвейера. По умолчанию удаление HttpClient удаляет и весь конвейер обработчиков; IHttpClientFactory отделяет жизенный цикл HttpClient от базового HttpClientHandler.
Такое разделение жизненного цикла позволяет решать проблемы сокетов и DNS двумя способами:

  • путём создания пула доступных обработчиковIHttpClientFactory поддерживает активный обработчик, который используется при создании всех HttpClient в течении двух минут, при этом при удалении HttpClient базовый обработчик не удаляется, тем самым соединение не закрывается;
  • периодически удаляя обработчики — каждые две минуты IHttpClientFactory создаёт новый активный обработчик, который используется для создания новых HttpClient.

Также IHttpClientFactory периодически удаляет обработчики с “истекшим сроком действия”, если они больще не используются HttpClient, обеспечивая использование ограниченного количества подключений1.

IHttpClientFactory по умолчанию включён в сервисы ASP.NET Core; нужно добавить его в сервисы приложения:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient();
}

Теперь мы можем получить объект IHttpClientFactory через внедрение зависимостей:

[ApiController]
public class ValuesController : ControllerBase
{
    private readonly IHttpClientFactory _factory;
    public ValuesController(IHttpClientFactory factory)
    {
        _factory = factory;
    }

    [HttpGet("values")]
    public async Task<string> GetRates()
    {
        HttpClient client = _factory.CreateClient();
        client.BaseAddress = new Uri("https://api.exchangeratesapi.io");
        client.DefaultRequestHeaders
            .Add(HeaderNames.UserAgent, "ExchangeRateViewer");

        var response = await client.GetAsync("latest");

        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();

    }
}

SocketsHttpHandler и IHttpClientFactory

Ограничения HttpClient, описанные в предыдущем разделе, применяются именно к HttpClientHandler. IHttpClientFactory управляет жизненным циклом и повторным использованием HttpClientHandler.
В .NET Core 2.1 была представлена замена HttpClientHandlerSocketsHttpHandler, в первую очередь нацеленная на повышение производительности и согласованности между платформами. Также SocketsHttpHandler можно настроить для использования пула соединений и повторного использования.
Несмотря на то, что использование IHttpClientFactory по прежнему предпочтительно, в сценарии, где нет внедрения зависимостей и где нельзя использовать IHttpClientFactory, можно активировать пул соединений SocketsHttpHandler, как описано здесь


  1. Подробнее об этом в блоге автора 


Последнее обновление : 11 мая 2023 г.
Дата создания : 30 октября 2022 г.

Комментарии

Комментарии