HttpClient и IHttpClientFactory, HeaderPropagation

↑ 3.1 Хост, конфигурация и middleware pipeline · ← Предыдущая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Классическая ошибка new HttpClient() на каждый запрос и знание Polly/resilience — признак опыта.

Объяснение

Два противоположных подводных камня:

  • Создавать HttpClient на каждый запрос — исчерпание сокетов (SocketException, TIME_WAIT).
  • Один статический HttpClient навсегда — DNS кэшируется, изменения адреса не подхватываются.

IHttpClientFactory решает оба: управляет пулом HttpMessageHandler и периодически пересоздаёт их.

builder.Services.AddHttpClient<IPaymentsClient, PaymentsClient>(c =>
{
    c.BaseAddress = new Uri("https://payments.internal/");
    c.Timeout = TimeSpan.FromSeconds(10);
})
.AddStandardResilienceHandler();   // retry, circuit breaker, timeout (Microsoft.Extensions.Http.Resilience)
 
public class PaymentsClient(HttpClient http) : IPaymentsClient
{
    public async Task<PaymentDto?> GetAsync(Guid id, CancellationToken ct)
        => await http.GetFromJsonAsync<PaymentDto>($"payments/{id}", ct);
}
СпособКогда
Typed clientклиент к конкретному сервису с методами
Named clientнесколько настроек одним типом
CreateClient()простые случаи

Проброс заголовков

builder.Services.AddHeaderPropagation(o => { o.Headers.Add("X-Correlation-Id"); o.Headers.Add("Authorization"); });
builder.Services.AddHttpClient<IPaymentsClient, PaymentsClient>().AddHeaderPropagation();
app.UseHeaderPropagation();

Так входящие заголовки автоматически копируются в исходящие запросы к другим сервисам.

Устойчивость

Retry с экспоненциальной паузой и jitter, circuit breaker, timeout на попытку и общий. Повторять можно только идемпотентные запросы.

Нюансы и подводные камни

  • Всегда передавайте CancellationToken.
  • Проверяйте EnsureSuccessStatusCode() или статус: 4xx/5xx не бросают исключение сами.
  • Читайте тело потоком, а HttpResponseMessage освобождайте (using).
  • Timeout клиента не заменяет таймаут на попытку в resilience handler.
  • Не логируйте заголовок Authorization.

Практика

  1. Настройте typed client с retry и circuit breaker и сымитируйте падение сервиса.
  2. Пробросьте X-Correlation-Id между двумя своими сервисами.
  3. Воспроизведите исчерпание сокетов в цикле с new HttpClient().

Вопросы с ответами

Связанные темы