Udostępnij za pośrednictwem


Wskazówki dotyczące korzystania z klienta HttpClient

Klasa System.Net.Http.HttpClient wysyła żądania HTTP i odbiera odpowiedzi HTTP z zasobu zidentyfikowanego przez identyfikator URI. Instancja HttpClient to zbiór ustawień, które są stosowane do wszystkich żądań wykonywanych przez tę instancję, a każda instancja używa własnej puli połączeń, co zapewnia izolację jej żądań od innych. Począwszy od platformy .NET Core 2.1, SocketsHttpHandler klasa zapewnia implementację, dzięki czemu zachowanie jest spójne na wszystkich platformach.

Zachowanie DNS

HttpClient Rozpoznaje tylko wpisy DNS po utworzeniu połączenia. Nie śledzi żadnych czasów życia (TTL), które są określone przez serwer DNS. Jeśli wpisy DNS zmieniają się regularnie, co może się zdarzyć w niektórych scenariuszach, klient nie będzie przestrzegać tych aktualizacji. Aby rozwiązać ten problem, można ograniczyć okres istnienia połączenia, ustawiając PooledConnectionLifetime właściwość , aby wyszukiwanie DNS było powtarzane po zastąpieniu połączenia. Rozważmy następujący przykład:

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

Poprzednia konfiguracja HttpClient służy do ponownego używania połączeń przez 15 minut. Po upływie przedziału czasu określonego przez PooledConnectionLifetime i zakończeniu ostatniego skojarzonego żądania (jeśli istnieje), to połączenie zostanie zamknięte. Jeśli w kolejce są oczekujące żądania, w razie potrzeby zostanie utworzone nowe połączenie.

Interwał 15-minutowy został wybrany arbitralnie do celów ilustracyjnych. Należy wybrać wartość na podstawie oczekiwanej częstotliwości zmian w systemie DNS lub innych zmianach sieci.

Połączenia w puli

Pula połączeń dla elementu HttpClient jest połączona z bazowym SocketsHttpHandlerelementem . HttpClient Gdy wystąpienie zostanie usunięte, usuwa wszystkie istniejące połączenia wewnątrz puli. Jeśli później wyślesz żądanie do tego samego serwera, należy ponownie utworzyć nowe połączenie. W związku z tym występuje spadek wydajności z powodu niepotrzebnego tworzenia połączenia. Ponadto porty TCP nie są zwalniane natychmiast po zamknięciu połączenia. (Aby uzyskać więcej informacji na ten temat, zobacz TCP TIME-WAIT w RFC 9293). Jeśli szybkość żądań jest wysoka, limit systemu operacyjnego dostępnych portów może zostać wyczerpany. Aby uniknąć problemów z wyczerpaniem portów, zalecamy ponowne używanie HttpClient wystąpień dla jak największej liczby żądań HTTP.

Aby podsumować zalecane HttpClient użycie w zakresie zarządzania okresem istnienia, należy użyć klientów długożyjących i ustawić PooledConnectionLifetime (.NET Core i .NET 5+) lub klientów krótkotrwałych utworzonych przez IHttpClientFactory.

  • W programach .NET Core i .NET 5+:

    • Użyj instancji singletona static z ustawionym interwałem HttpClient takim jak 2 minuty, w zależności od oczekiwanych zmian DNS. Rozwiązuje to zarówno problemy z wyczerpaniem portów, jak i zmianami DNS bez dodawania IHttpClientFactory. Jeśli musisz mieć możliwość wyśmiewać program obsługi, możesz zarejestrować go oddzielnie.

    Napiwek

    Jeśli używasz tylko ograniczonej liczby HttpClient wystąpień, jest to również akceptowalna strategia. Ważne jest, aby nie były tworzone i usuwane z każdym żądaniem, ponieważ każdy z nich zawiera pulę połączeń. Użycie więcej niż jednego wystąpienia jest niezbędne w scenariuszach z wieloma serwerami proxy lub do oddzielenia kontenerów plików cookie bez całkowitego wyłączania obsługi plików cookie.

    • Za pomocą programu IHttpClientFactorymożna mieć wielu, inaczej skonfigurowanych klientów dla różnych przypadków użycia. Należy jednak pamiętać, że klienci utworzoni przez fabrykę mają być krótkotrwałi, a po utworzeniu klienta fabryka nie ma już nad nią kontroli.

      Wystąpienia pul HttpMessageHandler fabryki i, jeśli jego okres istnienia nie wygasł, program obsługi można użyć ponownie z puli, gdy fabryka utworzy nowe HttpClient wystąpienie. Ponowne użycie pozwala uniknąć problemów z wyczerpaniem gniazd.

      Jeśli zależy ci na konfigurowalności, jaką zapewnia IHttpClientFactory, zalecamy użycie podejścia typizowanego klienta .

  • W programie .NET Framework użyj polecenia IHttpClientFactory do zarządzania wystąpieniami HttpClient . Jeśli nie używasz fabryki i zamiast tego utworzysz nowe wystąpienie klienta dla każdego żądania samodzielnie, możesz wyczerpać dostępne porty.

    Ostrzeżenie

    Jeśli aplikacja wymaga plików cookie, zaleca się unikanie korzystania z usługi IHttpClientFactory. Agregowanie HttpMessageHandler wystąpień powoduje udostępnianie CookieContainer obiektów. Nieprzewidziane CookieContainer udostępnianie może spowodować wyciek plików cookie między niepowiązanymi częściami aplikacji. Ponadto, gdy HandlerLifetime wygaśnie, program obsługi zostanie ponownie wykorzystany, co oznacza, że wszystkie pliki cookie przechowywane w jego CookieContainer zostaną utracone.

Aby uzyskać więcej informacji na temat zarządzania okresem trwałości HttpClient za pomocą IHttpClientFactory, zobacz IHttpClientFactory wytyczne.

Odporność na statycznych klientów

Istnieje możliwość skonfigurowania static lub singleton klienta do używania dowolnej liczby potoków odporności zgodnie z następującym wzorcem:

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

class MyClass
{
    static HttpClient? s_httpClient;

    MyClass()
    {
        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,
        };

        s_httpClient = new HttpClient(resilienceHandler);
    }
}

Poprzedni kod:

  • Opiera się na pakiecie NuGet Microsoft.Extensions.Http.Resilience .
  • Określa przejściowy uchwyt błędów HTTP, skonfigurowany z potokiem ponawiania, który z każdą próbą będzie wykładniczo zwiększał opóźnienie między próbami.
  • Ustala czas życia połączenia w puli na piętnaście minut dla elementu socketHandler.
  • Przekazuje socketHandler do resilienceHandler z użyciem logiki ponawiania.
  • Tworzy wystąpienie udostępnione HttpClient dla elementu resilienceHandler.

Zobacz też