Как лучше организовать настройку базового адреса HTTP клиента: в клиенте или в отдельном сервисе
Что проверяют
Знаете ли вы, как в .NET правильно живёт HttpClient, и отличаете ли настройку транспорта от бизнес-логики. Подвох в том, что «отдельный сервис, который создаёт клиентов» часто оказывается велосипедом поверх IHttpClientFactory. Следом спрашивают, почему нельзя делать new HttpClient() на каждый запрос.
Как отвечать
Лучший вариант ни то ни другое в чистом виде: адрес задаётся при регистрации клиента в DI, а берётся из конфигурации.
- типизированный клиент:
services.AddHttpClient<CatalogClient>((sp, c) => ...), адрес читается изappsettings.jsonчерезIOptions<CatalogOptions>. СамCatalogClientполучает готовыйHttpClientв конструктор и знает только относительные пути; - именованный клиент:
AddHttpClient("catalog", ...)иIHttpClientFactory.CreateClient("catalog"), когда клиентов много и типизировать каждый незачем; - обнаружение сервисов: в Aspire адрес вида
https+http://catalogрезолвится черезAddServiceDiscovery(), и хоста в коде нет вовсе.
Почему фабрика: она держит пул HttpMessageHandler и пересоздаёт обработчики (по умолчанию раз в две минуты), поэтому сокеты не исчерпываются и смена DNS подхватывается. Сюда же навешивается AddStandardResilienceHandler() с повторами и таймаутами.
В итоге адрес меняется без пересборки, в тестах клиент получает HttpClient с фейковым HttpMessageHandler, а бизнес-логика зависит от интерфейса клиента, а не от URL.
Где спотыкаются
Пишут «сервис», который на каждый вызов делает new HttpClient { BaseAddress = ... }. Под нагрузкой сокеты копятся в TIME_WAIT. Обратная крайность, один статический клиент без PooledConnectionLifetime, не видит смену DNS.
Теряют часть пути. При BaseAddress = new Uri("https://api.example.com/v1") вызов GetAsync("orders") уйдёт на https://api.example.com/orders. Нужен слэш в конце адреса и относительный путь без слэша в начале.
Меняют BaseAddress или Timeout после первого запроса. HttpClient бросает InvalidOperationException: настройки фиксируются до первой отправки.