Richtlinien für die Verwendung von HttpClient

Die System.Net.Http.HttpClient-Klasse sendet HTTP-Anforderungen und empfängt HTTP-Antworten von einer Ressource, die durch einen URI identifiziert wird. Eine HttpClient-Instanz ist eine Sammlung von Einstellungen, die auf alle von dieser Instanz ausgeführten Anforderungen angewendet wird, und jede Instanz verwendet einen eigenen Verbindungspool, der ihre Anforderungen von anderen isoliert. Ab .NET Core 2.1 stellt die SocketsHttpHandler-Klasse die Implementierung bereit, sodass das Verhalten auf allen Plattformen konsistent ist.

DNS-Verhalten

HttpClient löst DNS-Einträge nur auf, wenn eine Verbindung erstellt wird. Die vom DNS-Server angegebene Gültigkeitsdauer (Time To Live, TTL) wird nicht nachverfolgt. Wenn sich DNS-Einträge regelmäßig ändern, was in einigen Szenarien vorkommen kann, berücksichtigt der Client diese Updates nicht. Um dieses Problem zu beheben, können Sie die Gültigkeitsdauer der Verbindung einschränken, indem Sie die PooledConnectionLifetime-Eigenschaft festlegen, sodass die DNS-Suche wiederholt wird, wenn die Verbindung ersetzt wird. Betrachten Sie das folgenden Beispiel:

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

Der vorherige HttpClient ist so konfiguriert, dass Verbindungen 15 Minuten lang wiederverwendet werden. Nach Ablauf des von PooledConnectionLifetime angegebenen Zeitintervalls und nachdem die Verbindung die letzte zugehörige Anforderung (falls vorhanden) abgeschlossen hat, wird diese Verbindung geschlossen. Wenn es Anforderungen gibt, die in der Warteschlange warten, wird nach Bedarf eine neue Verbindung erstellt.

Das 15-Minuten-Intervall wurde willkürlich zur Veranschaulichung gewählt. Sie sollten den Wert basierend auf der erwarteten Häufigkeit von DNS- oder anderen Netzwerkänderungen auswählen.

Gepoolte Verbindungen

Der Verbindungspool für einen HttpClient ist mit dem zugrunde liegenden SocketsHttpHandler verknüpft. Wenn die HttpClient-Instanz verworfen wird, werden alle vorhandenen Verbindungen innerhalb des Pools verworfen. Wenn Sie später eine Anforderung an denselben Server senden, muss eine neue Verbindung erstellt werden. Daher gibt es eine Leistungsstrafe für die unnötige Verbindungserstellung. Darüber hinaus werden TCP-Ports nicht sofort nach dem Schließen der Verbindung freigegeben. (Weitere Informationen hierzu finden Sie unter „TCP TIME-WAIT“ in RFC 9293.) Bei hoher Anforderungsrate ist das Betriebssystemlimit der verfügbaren Ports möglicherweise erschöpft. Um Porterschöpfungsprobleme zu vermeiden, wird empfohlen, HttpClient-Instanzen für möglichst viele HTTP-Anforderungen wiederzuverwenden.

Als Zusammenfassung der empfohlenen HttpClient-Verwendung in Bezug auf die Lebensdauerverwaltung sollten Sie entweder langlebige Clients mit eingerichteter PooledConnectionLifetime (.NET Core und .NET 5 oder höher) verwenden oder kurzlebige Clients, die von IHttpClientFactory erstellt werden.

  • In .NET Core und .NET 5 oder höher:

    • Verwenden Sie eine HttpClient-Instanz vom Typ static oder Singleton, wobei PooledConnectionLifetime auf das gewünschte Intervall festgelegt ist, z. B. 2 Minuten, je nach erwarteten DNS-Änderungen. Dadurch werden sowohl die Probleme mit Porterschöpfung als auch bei DNS-Änderungen behoben, ohne den Mehraufwand von IHttpClientFactory hinzuzufügen. Wenn Sie In der Lage sein müssen, Ihren Handler zu simulieren, können Sie ihn separat registrieren.

    Tipp

    Wenn Sie nur eine begrenzte Anzahl von HttpClient-Instanzen verwenden, ist dies ebenfalls eine akzeptable Strategie. Es kommt darauf an, dass sie nicht mit jeder Anforderung erstellt und verworfen werden, da sie jeweils einen Verbindungspool enthalten. Die Verwendung mehrerer Instanzen ist für Szenarien mit mehreren Proxys oder zum Trennen von Cookiecontainern erforderlich, ohne die Cookieverarbeitung vollständig zu deaktivieren.

    • Mit IHttpClientFactory können Sie mehrere, unterschiedlich konfigurierte Clients für unterschiedliche Anwendungsfälle verwenden. Beachten Sie jedoch, dass die von der Factory erstellten Clients kurzlebig sein sollen, und sobald der Client erstellt wurde, besitzt die Factory keine Kontrolle mehr darüber.

      Die Factory poolt HttpMessageHandler-Instanzen, und wenn seine Gültigkeitsdauer noch nicht abgelaufen ist, kann ein Handler aus dem Pool wiederverwendet werden, wenn die Factory eine neue HttpClient-Instanz erstellt. Durch diese Wiederverwendung werden Probleme mit Socketerschöpfung vermieden.

      Wenn Sie die Konfigurierbarkeit wünschen, die IHttpClientFactory bereitstellt, wird empfohlen, den Ansatz mit typisierten Clients zu verwenden.

  • Verwenden Sie in .NET Framework IHttpClientFactory, um Ihre HttpClient-Instanzen zu verwalten. Wenn Sie die Factory nicht verwenden und stattdessen für jede Anforderung selbst eine neue Clientinstanz erstellen, können Sie die verfügbaren Ports erschöpfen.

    Tipp

    Wenn Ihre App Cookies erfordert, sollten Sie ggf. automatische Cookieverarbeitung deaktivieren oder IHttpClientFactory vermeiden. Das Poolen der HttpMessageHandler-Instanzen führt zur Freigabe von CookieContainer-Objekten. Die unerwartete Freigabe von CookieContainer-Objekten führt oft zu fehlerhaftem Code.

Weitere Informationen zum Verwalten der HttpClient-Lebensdauer mit IHttpClientFactory finden Sie unter IHttpClientFactory-Richtlinien.

Resilienz bei statischen Clients

Es ist mithilfe des folgenden Musters möglich, einen static- oder Singleton-Client so zu konfigurieren, dass eine beliebige Anzahl von Resilienzpipelines verwendet wird:

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

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,
};

var httpClient = new HttpClient(resilienceHandler);

Der vorangehende Code:

  • Basiert auf dem NuGet-Paket Microsoft.Extensions.Http.Resilience.
  • Gibt einen vorübergehenden HTTP-Fehlerhandler an, der mit einer Wiederholungspipeline konfiguriert ist, die bei jedem Versuch ein exponentielles Backoff für Verzögerungsintervalle durchführt.
  • Definiert eine gepoolte Verbindungslebensdauer von 15 Minuten für socketHandler.
  • Übergibt socketHandler mit der Wiederholungslogik an resilienceHandler.
  • Instanziiert HttpClient mit resilienceHandler.

Wichtig

Die Microsoft.Extensions.Http.Resilience Bibliothek ist derzeit als experimentell gekennzeichnet und kann sich in Zukunft ändern.

Weitere Informationen