N'enfermez pas HttpClient dans un using — la communication HTTP en C# pour applications métier (modèles de création, délais d'expiration, tentatives)

· · CSharp, .NET, HttpClient, IHttpClientFactory, Réseau, async/await, Développement Windows, Conseil technique

« En début d’après-midi, les connexions vers l’API externe se mettent à échouer avec une SocketException » ; « après avoir basculé le serveur de destination, l’application continue de se connecter à l’ancien serveur » — le HttpClient de C# est simple d’usage tant qu’on se contente d’appeler GetAsync, mais si l’on se trompe sur la façon de créer et de conserver l’instance, on introduit ce type de dysfonctionnement qui « fonctionne au départ mais casse une fois en production ».

Cet article part de l’hypothèse d’une application métier Windows appelant une API Web externe ou un service interne, et présente dans l’ordre pratique où l’on hésite le plus souvent : le bon modèle de création de HttpClient, la conception des délais d’expiration, les tentatives, la gestion des erreurs, et enfin les pièges propres à l’environnement Windows.

1. Conclusion d’abord (tableau de décision)

La façon de conserver HttpClient dépend de l’architecture de l’application. Commençons par un tableau de décision.

Type d’application Modèle recommandé Raison
Outil console de courte durée (quelques secondes à quelques minutes) (.NET) Une seule instance HttpClient static/singleton Pour un processus de courte durée, le problème de changement de DNS est en pratique négligeable
Application ou service Windows résidant longtemps (.NET, sans DI) HttpClient static + configuration de SocketsHttpHandler.PooledConnectionLifetime Résout à la fois l’épuisement de sockets et le problème de changement de DNS
Application utilisant Generic Host / DI (.NET) IHttpClientFactory (AddHttpClient) Le pool et le remplacement des handlers sont délégués à la fabrique ; les clients nommés/typés permettent de séparer la configuration par destination
Application .NET Framework Introduire IHttpClientFactory via le paquet Microsoft.Extensions.Http Sous .NET Framework, la création manuelle entraîne facilement un épuisement de ports, et l’usage de la fabrique est également recommandé officiellement1
Le proxy, les cookies ou les certificats diffèrent selon la destination Séparer un HttpClient par configuration (ne pas le réutiliser) La configuration de connexion du handler ne peut plus être modifiée après l’envoi de la première requête2

Cela posé, voici les conclusions à retenir d’emblée.

  • Ne faites pas new HttpClient() à chaque requête pour le détruire ensuite avec using. HttpClient maintient en interne un pool de connexions et est conçu pour être réutilisé. Le créer et le détruire à chaque fois épuise les sockets disponibles sous forte charge et provoque une SocketException2.
  • Mais le rendre simplement static ne suffit pas non plus. HttpClient ne résout le DNS qu’à la création de la connexion, si bien qu’il continue d’utiliser l’ancienne connexion même quand l’adresse IP de destination change. La solution officiellement recommandée consiste à limiter la durée de vie des connexions avec SocketsHttpHandler.PooledConnectionLifetime1.
  • Si vous utilisez Generic Host ou un conteneur DI, déléguez à IHttpClientFactory. La fabrique met les handlers en pool et les remplace par défaut toutes les 2 minutes, ce qui traite à la fois l’épuisement de sockets et les changements de DNS3.
  • Le délai d’expiration par défaut est de 100 secondes. Pour une application métier, cette durée équivaut en pratique à un blocage infini ; définissez donc une valeur explicite pour chaque destination selon les besoins.
  • N’implémentez pas vos propres tentatives : partez du handler standard de Microsoft.Extensions.Http.Resilience. Il permet d’introduire tentatives, disjoncteur (circuit breaker) et délais d’expiration avec un ensemble de valeurs par défaut éprouvées, et évite dès la conception des incidents typiques d’une boucle de tentatives maison, comme un POST échoué renvoyé sans condition et créant un double enregistrement4.

2. Pourquoi « créer une instance à chaque using » pose problème ── l’épuisement de sockets

Comme HttpClient implémente IDisposable, le code suivant paraît correct à première vue.

// Anti-pattern : création et destruction à chaque requête
public async Task<string> GetDataAsync(string url)
{
    using var client = new HttpClient();
    return await client.GetStringAsync(url);
}

Le problème est que, même après Dispose, le socket n’est pas libéré immédiatement au niveau du système d’exploitation. Selon la spécification TCP, le socket du côté qui ferme la connexion reste un certain temps à l’état TIME_WAIT. Tant que la fréquence d’appel reste faible, rien ne se produit, mais quand la charge augmente, les sockets non libérés s’accumulent et, à un moment donné, la connexion échoue soudainement avec une SocketException2.

Ce qui rend ce défaut redoutable, c’est qu’il ne se reproduit quasiment jamais en développement ou en test. Il se manifeste plutôt sous la forme de pannes limitées aux heures de forte affluence en production, ou uniquement pendant le traitement par lots de fin de mois. Pour l’investiguer, vérifier le nombre de sockets en TIME_WAIT avec la commande suivante au moment où le symptôme survient permet de cibler la cause.

# Compter le nombre de sockets en TIME_WAIT par destination
netstat -ano | Select-String "TIME_WAIT" | Measure-Object

Notez que le HttpClient obtenu via IHttpClientFactory n’est pas concerné par ce problème. Pour un client produit par la fabrique, Dispose ne détruit pas le handler (l’entité réelle du pool de connexions), donc l’enfermer dans un using est sans danger3.

3. Se contenter de static ne suffit pas ── le problème du changement de DNS

Rendre HttpClient static pour lutter contre l’épuisement de sockets va dans la bonne direction, mais cela laisse subsister un autre problème. HttpClient ne résout le DNS qu’à la création de la connexion et ne tient même pas compte du TTL des enregistrements DNS2. Tant que la connexion reste vivante dans le pool, elle continue de pointer vers l’ancienne adresse IP même si l’adresse de destination change.

L’incident du type « le DNS a basculé lors d’un failover, mais l’application a continué de pointer vers l’ancien serveur jusqu’au redémarrage » s’explique par ce mécanisme. La solution recommandée par les directives officielles consiste à limiter la durée de vie des connexions avec SocketsHttpHandler.PooledConnectionLifetime1.

// Modèle recommandé sous .NET (Core) / .NET 5+ :
// recréer périodiquement la connexion pour suivre les changements de DNS
private static readonly HttpClient SharedClient = new(new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(2)
});

Une connexion arrivée en fin de vie est recréée lors de la requête suivante, moment où le DNS est de nouveau résolu. La valeur à choisir dépend de la rapidité avec laquelle vous souhaitez suivre les changements de DNS. L’exemple de la documentation officielle utilise 2 minutes, mais pour un système interne dont la destination change rarement, une valeur plus longue ne pose pas de problème1.

Notez que SocketsHttpHandler est une implémentation disponible depuis .NET Core 2.1 et n’est pas utilisable sous .NET Framework. Pour .NET Framework, utilisez IHttpClientFactory, présenté dans le chapitre suivant1.

4. Avec DI, utilisez IHttpClientFactory

Pour les applications utilisant Generic Host ou un conteneur DI, IHttpClientFactory (AddHttpClient) est le premier choix. Pour une explication du Generic Host lui-même, consultez « Qu’est-ce que le Generic Host ? », et pour son introduction dans une application de bureau, « Utiliser Generic Host + BackgroundService dans une application de bureau ».

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

// Client nommé : séparer la configuration par destination
builder.Services.AddHttpClient("OrderApi", client =>
{
    client.BaseAddress = new Uri("https://order.example.co.jp/");
    client.Timeout = TimeSpan.FromSeconds(10);
});

Il y a trois points à retenir sur le comportement de la fabrique.

  • Les handlers sont mis en pool et remplacés par défaut toutes les 2 minutes. Chaque appel à CreateClient renvoie un nouveau HttpClient, mais le handler sous-jacent (le pool de connexions) est partagé, ce qui évite l’épuisement de sockets, et le remplacement périodique permet de suivre les changements de DNS3.
  • Un HttpClient produit par la fabrique est censé être utilisé de façon éphémère. Si vous conservez l’instance reçue dans un champ singleton, elle ne participe plus au remplacement des handlers et cesse de suivre les changements de DNS. Pour la même raison, évitez également d’injecter un client typé dans un service singleton3.
  • Les applications dépendant des cookies demandent une attention particulière. Le fait que les handlers soient mis en pool entraîne un partage involontaire du CookieContainer. Si vous utilisez des cookies, la documentation officielle recommande soit d’éviter la fabrique, soit de désactiver la gestion des cookies et d’ajouter vous-même les en-têtes1.

Pour la récupération de jeton lors de l’appel d’une API authentifiée (par exemple une API protégée par Microsoft Entra ID), voir « Intégrer l’authentification Entra ID dans une application WinForms/WPF ».

5. Conception des délais d’expiration ── les 100 secondes par défaut sont trop longues pour une application métier

La valeur par défaut de HttpClient.Timeout est de 100 secondes5. Pour une application métier qui appelle une API dans le prolongement d’une action à l’écran, faire attendre l’utilisateur 100 secondes revient à un blocage ; il faut donc définir explicitement une valeur pour chaque destination.

// Délai d'expiration par défaut pour l'ensemble du client
client.Timeout = TimeSpan.FromSeconds(10);

// Pour raccourcir/allonger le délai d'une requête particulière, utilisez CancellationTokenSource
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
HttpResponseMessage response = await client.GetAsync(url, cts.Token);

Voici les points d’attention pour la conception.

  • L’exception levée en cas de délai d’expiration est TaskCanceledException. Depuis .NET 5, un délai d’expiration causé par HttpClient.Timeout contient une TimeoutException en exception interne5. En revanche, un délai d’expiration provoqué par un CancellationTokenSource maison comme ci-dessus n’a pas d’exception interne. Pour distinguer de façon fiable un délai d’expiration d’une annulation initiée par l’utilisateur, mieux vaut se baser non pas sur l’exception interne mais sur le fait que « le token transmis par l’appelant est déjà annulé ou non » (voir l’exemple de code du chapitre 7). Attention : si votre bloc catch ne surveille que HttpRequestException, vous laisserez passer les délais d’expiration.
  • Timeout est une limite portant sur « la requête entière ». Si vous souhaitez limiter uniquement l’établissement de la connexion à une durée courte, combinez-le avec SocketsHttpHandler.ConnectTimeout. Une exigence du type « abandonner au bout de 3 secondes si le serveur est en panne, mais attendre jusqu’à 60 secondes pour une réponse volumineuse en fonctionnement normal » peut s’exprimer en combinant ces deux réglages2.
  • Pour le téléchargement de fichiers volumineux, évitez la mise en mémoire tampon par défaut. HttpClient charge par défaut la réponse entière en mémoire ; pour un téléchargement de plusieurs dizaines de Mo ou plus, spécifiez HttpCompletionOption.ResponseHeadersRead afin de traiter la réponse en flux2.

Pour extraire les valeurs de délai d’expiration dans appsettings.json et les faire varier selon l’environnement, le tableau de décision de « Au-delà de appsettings.json — guide pratique de la gestion de configuration dans les applications métier Windows » s’applique tel quel.

Notez également que bloquer avec .Result ou .Wait() lors d’un appel HTTP depuis WinForms/WPF provoque un blocage mortel (deadlock) du thread d’interface utilisateur. Ce piège classique est détaillé dans « Tableau de décision pratique pour async/await en C# », dont la lecture est recommandée avant d’écrire du code de communication.

6. Tentatives (retry) ── utilisez le handler resilience standard plutôt qu’une boucle maison

Le réseau échoue par nature de façon transitoire, si bien que tout appel à une API externe nécessite des tentatives de nouvel essai. Cependant, une implémentation maison à base de boucle for et de Task.Delay oblige à implémenter correctement, soi-même, tous les points suivants — ce qui n’en vaut pas la peine.

  • Distinguer les échecs qu’il est légitime de rejouer (délai d’expiration, HTTP 408/429/5xx) de ceux où cela ne sert à rien (HTTP 400/401/404)
  • Exclure les méthodes HTTP dont la réexécution provoque un incident (double exécution d’un enregistrement via POST, par exemple)
  • Le backoff exponentiel et la gigue (jitter) — la variation aléatoire qui évite que tous les clients ne renvoient leur requête simultanément et ne fassent à nouveau tomber le serveur
  • Un disjoncteur (circuit breaker) qui arrête les appels eux-mêmes lorsque la panne persiste

Le handler standard du paquet Microsoft.Extensions.Http.Resilience fournit cet ensemble complet avec des valeurs par défaut éprouvées4.

builder.Services.AddHttpClient("OrderApi", client =>
    {
        client.BaseAddress = new Uri("https://order.example.co.jp/");
    })
    .AddStandardResilienceHandler(); // Ensemble standard tentatives + disjoncteur + délai d'expiration

Les valeurs par défaut du handler standard sont les suivantes : délai d’expiration de 30 secondes pour la requête entière, jusqu’à 3 tentatives avec backoff exponentiel (délai initial de 2 secondes, avec gigue), délai d’expiration de 10 secondes par tentative, et une configuration traitant HTTP 408/429/5xx ainsi que HttpRequestException comme des erreurs transitoires4.

Un point à surveiller dans les valeurs par défaut : le handler standard rejoue par défaut toutes les méthodes HTTP. Pour une API où un double enregistrement via POST poserait problème, désactivez les tentatives sur les méthodes non sûres4.

httpClientBuilder.AddStandardResilienceHandler(options =>
{
    // Désactiver la réexécution pour POST/PUT/DELETE, etc.
    options.Retry.DisableForUnsafeHttpMethods();
});

Notez enfin que les tentatives ne résolvent que des échecs transitoires. Des symptômes tels qu’une connexion établie mais sans transfert de données, ou une réponse extrêmement lente, relèvent souvent d’un problème de la couche TCP ; la méthode de diagnostic présentée dans « Retransmission TCP et RFC1323 ── enquête sur un arrêt de communication de caméra industrielle » peut alors être utile.

7. Gestion des erreurs ── comment traiter les codes de statut

HttpClient ne lève pas d’exception pour un échec « au sens HTTP » comme un 404 ou un 500, où une réponse a bien été reçue. Une exception ne survient que lorsque la réponse elle-même n’a pas pu être obtenue : échec de connexion, délai d’expiration, annulation, etc. Il faut écrire le code en distinguant clairement ces deux catégories.

try
{
    using HttpResponseMessage response = await client.GetAsync(url, ct);

    if (!response.IsSuccessStatusCode)
    {
        // La réponse est arrivée mais en échec : on peut brancher selon le code de statut
        if (response.StatusCode == HttpStatusCode.NotFound)
        {
            return null; // Exemple traitant « n'existe pas » comme un cas normal
        }
        response.EnsureSuccessStatusCode(); // Pour le reste, on bascule vers HttpRequestException
    }

    return await response.Content.ReadFromJsonAsync<Order>(ct);
}
catch (HttpRequestException ex)
{
    // Échec de connexion, ou statut d'échec provenant d'EnsureSuccessStatusCode.
    // Depuis .NET 5, ex.StatusCode permet de consulter le code de statut de l'échec
    logger.LogError(ex, "Échec de l'appel à l'API de commandes. StatusCode={StatusCode}", ex.StatusCode);
    throw;
}
catch (TaskCanceledException) when (ct.IsCancellationRequested)
{
    // Annulation via le token transmis par l'appelant (fermeture de l'écran, etc.).
    // Ce n'est pas une erreur : on la laisse se propager sans polluer les logs
    throw;
}
catch (TaskCanceledException ex)
{
    // Expiration de HttpClient.Timeout, ou d'un CTS de délai d'expiration maison
    logger.LogError(ex, "Délai d'expiration dépassé lors de l'appel à l'API de commandes");
    throw;
}

Une décision comme « traiter un 404 en exception ou en null » dépend de la sémantique de l’API appelée. Si vous transformez systématiquement tout en exception avec un EnsureSuccessStatusCode unique, le bloc catch de l’appelant finit par grossir démesurément. La façon de tracer la frontière entre ce qui devient une exception et ce qui s’exprime par une valeur de retour peut reprendre telle quelle l’approche décrite dans « Pratique du catch d’exceptions, de la journalisation et de la gestion des erreurs ».

Pour l’envoi et la réception de JSON, l’utilisation de GetFromJsonAsync / PostAsJsonAsync / ReadFromJsonAsync de System.Net.Http.Json évite d’avoir à écrire soi-même une sérialisation en passant par des chaînes de caractères.

8. Pièges propres aux applications métier Windows

Pour finir, voici un récapitulatif des pièges couramment rencontrés en pratique dans un environnement Windows.

  • La détection automatique du proxy ralentit la première requête. Par défaut sous Windows, HttpClient utilise les paramètres de proxy du système d’exploitation (y compris la détection automatique). Si vous savez qu’aucun proxy n’est nécessaire, désactiver cette détection avec HttpClientHandler.UseProxy = false supprime le temps d’attente2. À l’inverse, dans un environnement où le proxy d’entreprise est obligatoire, le spécifier explicitement via WebProxy évite le classique « ça marche sur le poste de développement mais pas sur le serveur ».
  • Terminez la configuration du proxy avant la première requête. Les réglages de connexion du handler ne prennent plus effet s’ils sont modifiés après l’envoi d’une première requête2.
  • La valeur par défaut du nombre de connexions simultanées est exactement opposée entre .NET et .NET Framework. Sous .NET (SocketsHttpHandler), le nombre de connexions HTTP/1.1 simultanées est illimité par défaut, si bien qu’un grand nombre de requêtes parallèles peut faire croître indéfiniment le nombre de connexions et se heurter aux limites d’un pare-feu ou du serveur. Pour un traitement à forte concurrence, fixez une limite avec MaxConnectionsPerServer2. À l’inverse, sous .NET Framework, la valeur par défaut de ServicePointManager.DefaultConnectionLimit est faible (2 en environnement non-ASP.NET), ce qui provoque plutôt le problème inverse : les requêtes parallèles sont mises en attente en interne et finissent par expirer. Si vous devez augmenter la concurrence sous .NET Framework, relevez explicitement cette limite6.
  • Lorsque l’appel provient d’un service Windows, le contexte de proxy et de TLS diffère de celui d’un utilisateur. Le compte d’exécution du service ne dispose ni des paramètres de proxy ni des identifiants de l’utilisateur, ce qui constitue une cause classique de dysfonctionnement du type « ça marche pour l’utilisateur interactif mais pas pour le service ». Pour le contexte d’exécution propre aux services, voir « Créer et exploiter un service Windows ».
  • N’intégrez pas en dur dans le code les URL de destination ni les clés d’API. Confiez le changement de destination à un fichier de configuration (« Gestion pratique de la configuration ») et le stockage des informations secrètes à la méthode décrite dans « Éviter les configurations en clair grâce à DPAPI ».

Résumé

En pratique, la qualité de l’utilisation de HttpClient se joue moins sur « comment l’appeler » que sur « comment le conserver ». Créer une instance à chaque requête provoque un épuisement de sockets, et le rendre naïvement static empêche de suivre les changements de DNS — deux problèmes invisibles en cours de développement. Sous .NET, la réponse est une instance partagée avec PooledConnectionLifetime ou IHttpClientFactory ; sous .NET Framework, c’est l’introduction d’IHttpClientFactory. Il faut ensuite définir explicitement un délai d’expiration pour chaque destination et confier les tentatives au handler resilience standard — ce n’est qu’à ce prix que l’application métier est réellement conçue en tenant compte d’un réseau qui échoue de temps à autre.

La révision de la communication d’une application existante (pannes limitées aux heures de forte affluence, remise à plat de la conception des délais d’expiration, nouvelle implémentation d’une intégration avec une API externe) nécessite souvent d’examiner le code réel et l’environnement d’exploitation ; en cas de doute, n’hésitez pas à nous consulter.

Articles connexes

Domaines de conseil associés

KomuraSoft LLC assure le développement d’applications métier Windows incluant l’intégration avec des API externes, ainsi que le conseil technique pour l’investigation des dysfonctionnements de communication d’applications existantes (épuisement de sockets, délais d’expiration, échecs de connexion intermittents) et la définition d’une stratégie de correction.

Références

  1. Microsoft Learn, Guidelines for using HttpClient. Sur le fait que .NET Core/.NET 5+ doit utiliser soit un client de longue durée avec PooledConnectionLifetime configuré, soit un client de courte durée produit par IHttpClientFactory ; que .NET Framework doit privilégier IHttpClientFactory ; et que les applications utilisant des cookies devraient éviter IHttpClientFactory en raison du partage de CookieContainer 2 3 4 5 6

  2. Microsoft Learn, HttpClient Class. Sur le fait qu’une instanciation à chaque requête provoque un épuisement de sockets et une SocketException ; que le DNS n’est résolu qu’à la création de la connexion sans tenir compte du TTL ; que la configuration de connexion du handler ne peut plus être modifiée après la première requête ; que le nombre de connexions HTTP/1.1 simultanées est illimité par défaut ; sur la recommandation de traitement en flux pour les téléchargements volumineux ; et sur le comportement par défaut du proxy ainsi que sa désactivation via UseProxy 2 3 4 5 6 7 8 9

  3. Microsoft Learn, IHttpClientFactory with .NET. Sur le fait que la durée de vie par défaut du handler est de 2 minutes ; qu’un HttpClient produit par la fabrique est censé être utilisé de façon éphémère ; que le Dispose d’un client produit par la fabrique ne détruit pas le handler ; et que l’injection d’un client typé dans un singleton empêche de suivre les changements de DNS.  2 3 4

  4. Microsoft Learn, Build resilient HTTP apps: Key development patterns. Sur les cinq stratégies configurées par AddStandardResilienceHandler (limiteur de débit / délai d’expiration global de 30 secondes / jusqu’à 3 tentatives avec backoff exponentiel / disjoncteur / délai d’expiration de 10 secondes par tentative), sur les codes de statut (408/429/5xx) et exceptions concernés, et sur la désactivation des tentatives pour POST, etc. via DisableForUnsafeHttpMethods 2 3 4

  5. Microsoft Learn, HttpClient.Timeout Property. Sur le fait que la valeur par défaut est de 100 secondes, et que depuis .NET 5, un délai d’expiration lève une TaskCanceledException contenant une TimeoutException en exception interne.  2

  6. Microsoft Learn, ServicePointManager.DefaultConnectionLimit Property. Sur le fait que le nombre de connexions simultanées par défaut est de 10 pour les applications hébergées par ASP.NET, et de 2 pour les autres (applications de bureau, etc.). 

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

HttpClient implémente IDisposable, ne faut-il pourtant pas l'enfermer dans un using ?
Le problème vient de l'usage consistant à « créer puis détruire l'instance à chaque requête ». HttpClient maintient en interne un pool de connexions et est conçu pour être réutilisé pendant toute la durée de vie de l'application. Si vous le créez et le détruisez à chaque fois, les sockets restent un certain temps à l'état TIME_WAIT même après la destruction, ce qui épuise les sockets disponibles sous forte charge et provoque une SocketException. Il faut soit le détruire une seule fois à la fin de l'application, soit l'obtenir via IHttpClientFactory. Un HttpClient obtenu via la fabrique peut sans problème être enfermé dans un using, car son Dispose ne détruit pas le handler sous-jacent.
Faut-il migrer depuis WebClient ou HttpWebRequest du .NET Framework ?
Nous recommandons d'unifier tout nouveau code autour de HttpClient. WebClient et HttpWebRequest sont d'anciennes API maintenues uniquement pour la compatibilité, et Microsoft recommande également l'usage de HttpClient pour tout nouveau développement. Il n'est pas nécessaire de remplacer en bloc le code existant, mais en migrant progressivement vers HttpClient chaque fois que vous touchez au code de communication, la maintenance devient plus simple sur le plan du contrôle des délais d'expiration, du support async et de la facilité de test.
Combien de tentatives faut-il prévoir, et à quel intervalle ?
Plutôt que de définir ces valeurs vous-même, il est plus sûr de partir des valeurs par défaut du handler standard de Microsoft.Extensions.Http.Resilience (3 tentatives maximum, backoff exponentiel avec gigue, délai initial de 2 secondes). Ce qui compte le plus n'est pas le nombre de tentatives mais de déterminer « quelles requêtes peuvent être rejouées en toute sécurité » : pour les opérations comme un POST dont la réexécution peut créer un double enregistrement, désactivez la tentative par défaut, ou n'activez-la qu'après avoir garanti l'idempotence côté serveur (la propriété selon laquelle recevoir deux fois la même requête ne change pas le résultat).
Pourquoi la toute première requête est-elle extrêmement lente dans un environnement avec proxy d'entreprise ?
Par défaut sous Windows, HttpClient tente de détecter automatiquement le proxy, ce qui peut ralentir la première connexion le temps que cette détection s'exécute. Dans un environnement où l'on sait qu'aucun proxy n'est nécessaire (communication interne entre serveurs, par exemple), désactiver la détection automatique en mettant UseProxy à false sur HttpClientHandler améliore la situation. À l'inverse, dans un environnement d'entreprise où le proxy est obligatoire, spécifier celui-ci explicitement via WebProxy plutôt que de s'appuyer sur la détection automatique donne un comportement plus stable.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog