Instructions pour l’utilisation de HttpClient

La classe System.Net.Http.HttpClient envoie des requêtes HTTP et reçoit des réponses HTTP d’une ressource identifiée par un URI. Une instance HttpClient est une collection de paramètres appliqués à toutes les requêtes exécutées par cette instance, et chaque instance utilise son propre pool de connexions, qui isole ses requêtes des autres. À compter de .NET Core 2.1, la classe SocketsHttpHandler fournit l’implémentation, ce qui rend le comportement cohérent sur toutes les plateformes.

Comportement DNS

HttpClient résout uniquement les entrées DNS lors de la création d’une connexion. Il ne suit pas les durées de vie (TTL) spécifiées par le serveur DNS. Si les entrées DNS changent régulièrement, ce qui peut se produire dans certains scénarios, le client ne respecte pas ces mises à jour. Pour résoudre ce problème, vous pouvez limiter la durée de vie de la connexion en définissant la propriété PooledConnectionLifetime afin que la recherche DNS soit répétée lorsque la connexion est remplacée. Prenons l’exemple suivant :

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

Le HttpClient précédent est configuré pour réutiliser les connexions pendant 15 minutes. Une fois que l’intervalle de temps spécifié par PooledConnectionLifetime s’est écoulé et que la connexion a achevé sa dernière demande associée (le cas échéant), cette connexion est clôturée. Si des demandes se trouvent dans la file d’attente, une nouvelle connexion est créée en fonction des besoins.

L’intervalle de 15 minutes a été déterminé arbitrairement à des fins d’illustration. Vous devez choisir la valeur en fonction de la fréquence attendue du DNS ou d’autres modifications apportées au réseau.

Connexions groupées

Le pool de connexions d’un HttpClient est lié au SocketsHttpHandler sous-jacent. Lorsque l’instance HttpClient est supprimée, elle supprime toutes les connexions existantes à l’intérieur du pool. Si vous envoyez ultérieurement une demande au même serveur, une nouvelle connexion doit être recréée. Par conséquent, il y a une pénalité de performances pour la création de connexion inutile. De plus, les ports TCP ne sont pas libérés immédiatement après la fermeture de la connexion. (Pour plus d’informations à ce sujet, consultez TCP TIME-WAIT dans RFC 9293.) Si le taux de requêtes est élevé, la limite de ports disponibles du système d’exploitation peut être épuisée. Pour éviter les problèmes d’épuisement des ports, nous vous recommandons de réutiliser les instances HttpClient pour autant de requêtes HTTP que possible.

Pour résumer l’utilisation recommandée de HttpClient en termes de gestion de la durée de vie, vous devez utiliser des clients de longue durée et définir PooledConnectionLifetime (.NET Core et .NET 5+) ou des clients de courte durée créés par IHttpClientFactory.

  • Dans .NET Core et .NET 5+ :

    • Utilisez une instance static ou singletonHttpClient avec PooledConnectionLifetime défini sur l’intervalle souhaité, par exemple 2 minutes, en fonction des modifications DNS attendues. Cela résout à la fois l’épuisement des ports et les problèmes de modification de DNS sans ajouter la surcharge de IHttpClientFactory. Si vous devez être en mesure de simuler votre gestionnaire, vous pouvez l’inscrire séparément.

    Conseil

    Si vous utilisez uniquement un nombre limité d’instances HttpClient, il s’agit également d’une stratégie acceptable. Ce qui importe, c’est qu’elles ne sont pas créées et supprimées avec chaque requête, car elles contiennent chacune un pool de connexions. L’utilisation de plusieurs instances est nécessaire pour les scénarios avec plusieurs proxys ou pour séparer les conteneurs de cookies sans désactiver complètement la gestion des cookies.

    • À l’aide de IHttpClientFactory, vous pouvez avoir plusieurs clients configurés différemment pour différents cas d’usage. Toutefois, n’oubliez pas que les clients créés par la fabrique sont destinés à être de courte durée et qu’une fois le client créé, la fabrique n’a plus de contrôle sur celui-ci.

      La fabrique regroupe des instances HttpMessageHandler et, si leur durée de vie n’a pas expiré, un gestionnaire peut être réutilisé à partir du pool lorsque la fabrique crée une instance HttpClient. Cette réutilisation évite tout problème d’épuisement de socket.

      Si vous souhaitez la configurabilité offerte par IHttpClientFactory, nous vous recommandons d’utiliser l’approche Client typé.

  • Dans .NET Framework, utilisez IHttpClientFactory pour gérer vos instances HttpClient. Si vous n’utilisez pas la fabrique et que vous créez plutôt une instance cliente pour chaque requête vous-même, vous pouvez épuiser les ports disponibles.

    Conseil

    Si votre application nécessite des cookies, envisagez de désactiver la gestion automatique des cookies ou d’éviter IHttpClientFactory. Le regroupement des instances HttpMessageHandler entraîne le partage d’objets CookieContainer. Le partage d’objets CookieContainer imprévus entraîne souvent un code incorrect.

Pour plus d’informations sur la gestion de la durée de vie HttpClient avec IHttpClientFactory, consultez les recommandations IHttpClientFactory.

Résilience avec des clients statiques

Il est possible de configurer un client static ou singleton pour utiliser un nombre quelconque de pipelines de résilience en utilisant le modèle suivant :

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);

Le code précédent :

  • S’appuie sur le package NuGet Microsoft.Extensions.Http.Resilience.
  • Spécifie un gestionnaire d’erreurs HTTP temporaire, configuré avec un pipeline de nouvelles tentatives qui, à chaque tentative, entraîne un backoff exponentiel des intervalles de retard.
  • Définit une durée de vie de connexion groupée de quinze minutes pour le socketHandler.
  • Transmet le socketHandler au resilienceHandler avec la logique de nouvelle tentative.
  • Instancie une HttpClient instance de resilienceHandler.

Important

La bibliothèque Microsoft.Extensions.Http.Resilience est actuellement marquée comme expérimentale et peut changer à l’avenir.

Voir aussi