Quelle devrait être la HttpClient
durée de vie d'un client WebAPI?
Est-il préférable d'avoir une instance de HttpClient
pour plusieurs appels?
Quelle est la surcharge de création et de suppression d'une HttpClient
demande par requête, comme dans l'exemple ci-dessous (extrait de http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from- a-net-client ):
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// New code:
HttpResponseMessage response = await client.GetAsync("api/products/1");
if (response.IsSuccessStatusCode)
{
Product product = await response.Content.ReadAsAsync<Product>();
Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
}
}
c#
asp.net
web-services
asp.net-web-api
dotnet-httpclient
Bruno Pessanha
la source
la source
Stopwatch
classe pour la comparer. Mon estimation serait qu'il serait plus logique d'en avoir un seulHttpClient
, en supposant que toutes ces instances sont utilisées dans le même contexte.Réponses:
HttpClient
a été conçu pour être réutilisé pour plusieurs appels . Même sur plusieurs threads. LeHttpClientHandler
a des informations d'identification et des cookies qui sont destinés à être réutilisés lors d'appels. Avoir une nouvelleHttpClient
instance nécessite de reconfigurer tout cela. En outre, laDefaultRequestHeaders
propriété contient des propriétés destinées à plusieurs appels. Le fait de devoir réinitialiser ces valeurs à chaque demande annule le point.Un autre avantage majeur de
HttpClient
est la possibilité d'ajouterHttpMessageHandlers
dans le pipeline de demandes / réponses pour appliquer des préoccupations transversales. Il peut s'agir de la journalisation, de l'audit, de la limitation, de la gestion des redirections, de la gestion hors ligne, de la capture de métriques. Toutes sortes de choses différentes. Si un nouveau HttpClient est créé à chaque demande, tous ces gestionnaires de messages doivent être configurés à chaque demande et, d'une manière ou d'une autre, tout état au niveau de l'application qui est partagé entre les demandes de ces gestionnaires doit également être fourni.Plus vous utilisez les fonctionnalités de
HttpClient
, plus vous verrez que la réutilisation d'une instance existante a du sens.Cependant, le plus gros problème, à mon avis, est que lorsqu'une
HttpClient
classe est supprimée, elle disposeHttpClientHandler
, ce qui ferme ensuite de force laTCP/IP
connexion dans le pool de connexions géré parServicePointManager
. Cela signifie que chaque demande avec un nouveauHttpClient
nécessite le rétablissement d'une nouvelleTCP/IP
connexion.D'après mes tests, en utilisant HTTP simple sur un réseau local, le succès des performances est assez négligeable. Je soupçonne que c'est parce qu'il existe un keepalive TCP sous-jacent qui maintient la connexion ouverte même lorsque vous
HttpClientHandler
essayez de la fermer.Sur les demandes qui vont sur Internet, j'ai vu une histoire différente. J'ai vu une baisse de performance de 40% en raison de la nécessité de rouvrir la demande à chaque fois.
Je soupçonne que le coup sur une
HTTPS
connexion serait encore pire.Mon conseil est de conserver une instance de HttpClient pour la durée de vie de votre application pour chaque API distincte à laquelle vous vous connectez.
la source
which then forcibly closes the TCP/IP connection in the pool of connections that is managed by ServicePointManager
Êtes-vous sûr de cette déclaration? C'est difficile à croire.HttpClient
me ressemble à une unité de travail qui est censée être instanciée souvent.Si vous voulez que votre application évolue, la différence est ÉNORME! En fonction de la charge, vous verrez des chiffres de performance très différents. Comme le mentionne Darrel Miller, HttpClient a été conçu pour être réutilisé à travers les demandes. Cela a été confirmé par des membres de l'équipe de la BCL qui l'ont écrit.
Un projet récent que j'ai eu était d'aider un très grand détaillant informatique en ligne bien connu à évoluer pour le trafic du Black Friday / vacances pour certains nouveaux systèmes. Nous avons rencontré des problèmes de performances liés à l'utilisation de HttpClient. Depuis sa mise en œuvre
IDisposable
, les développeurs ont fait ce que vous feriez normalement en créant une instance et en la plaçant à l'intérieur d'uneusing()
instruction. Une fois que nous avons commencé les tests de charge, l'application a mis le serveur à genoux - oui, le serveur, pas seulement l'application. La raison en est que chaque instance de HttpClient ouvre un port sur le serveur. En raison de la finalisation non déterministe de GC et du fait que vous travaillez avec des ressources informatiques qui s'étendent sur plusieurs couches OSI , la fermeture des ports réseau peut prendre un certain temps. En fait le système d'exploitation Windows lui-mêmepeut prendre jusqu'à 20 secondes pour fermer un port (selon Microsoft). Nous ouvrions les ports plus rapidement qu'ils ne pouvaient être fermés - l'épuisement des ports du serveur qui a martelé le processeur à 100%. Ma solution consistait à changer le HttpClient en une instance statique qui a résolu le problème. Oui, c'est une ressource jetable, mais les frais généraux sont largement compensés par la différence de performances. Je vous encourage à faire des tests de charge pour voir comment votre application se comporte.Vous pouvez également consulter la page WebAPI Guidance pour obtenir de la documentation et des exemples à l' adresse https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
Portez une attention particulière à cet appel:
Si vous constatez que vous avez besoin d'utiliser un statique
HttpClient
avec des en-têtes, une adresse de base, etc. différents, vous devrez créer leHttpRequestMessage
fichier manuellement et définir ces valeurs sur leHttpRequestMessage
. Ensuite, utilisez leHttpClient:SendAsync(HttpRequestMessage requestMessage, ...)
MISE À JOUR pour .NET Core : vous devez utiliser
IHttpClientFactory
via Dependency Injection pour créer desHttpClient
instances. Il gérera la durée de vie pour vous et vous n'avez pas besoin de le supprimer explicitement. Voir Effectuer des requêtes HTTP à l'aide de IHttpClientFactory dans ASP.NET Corela source
Comme l'indiquent les autres réponses,
HttpClient
est destiné à être réutilisé. Cependant, la réutilisation d'une seuleHttpClient
instance dans une application multithread signifie que vous ne pouvez pas modifier les valeurs de ses propriétés avec état, commeBaseAddress
etDefaultRequestHeaders
(vous ne pouvez donc les utiliser que si elles sont constantes dans votre application).Une approche pour contourner cette limitation consiste à utiliser
HttpClient
une classe qui duplique toutes lesHttpClient
méthodes dont vous avez besoin (GetAsync
,PostAsync
etc.) et les délègue à un singletonHttpClient
. Cependant, c'est assez fastidieux (vous devrez également envelopper les méthodes d'extension ), et heureusement, il existe un autre moyen : continuer à créer de nouvellesHttpClient
instances, mais réutiliser le sous-jacentHttpClientHandler
. Assurez-vous simplement de ne pas supprimer le gestionnaire:la source
SendAsync
est beaucoup moins pratique que les méthodes dédiées telles quePutAsync
,PostAsJsonAsync
etc.Lié aux sites Web à volume élevé mais pas directement à HttpClient. Nous avons l'extrait de code ci-dessous dans tous nos services.
De https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Net.ServicePoint.ConnectionLeaseTimeout);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2); k (DevLang-csharp) & rd = vrai
"Vous pouvez utiliser cette propriété pour vous assurer que les connexions actives d'un objet ServicePoint ne restent pas ouvertes indéfiniment. Cette propriété est destinée aux scénarios dans lesquels les connexions doivent être supprimées et rétablies périodiquement, comme les scénarios d'équilibrage de charge.
Par défaut, lorsque KeepAlive a la valeur true pour une demande, la propriété MaxIdleTime définit le délai d'expiration pour la fermeture des connexions ServicePoint en raison de l'inactivité. Si le ServicePoint a des connexions actives, MaxIdleTime n'a aucun effet et les connexions restent ouvertes indéfiniment.
Lorsque la propriété ConnectionLeaseTimeout est définie sur une valeur autre que -1 et une fois le temps spécifié écoulé, une connexion ServicePoint active est fermée après avoir traité une demande en définissant KeepAlive sur false dans cette demande. La définition de cette valeur affecte toutes les connexions gérées par l'objet ServicePoint. »
Lorsque vous avez des services derrière un CDN ou un autre point de terminaison que vous souhaitez basculer, ce paramètre aide les appelants à vous suivre jusqu'à votre nouvelle destination. Dans cet exemple, 60 secondes après un basculement, tous les appelants doivent se reconnecter au nouveau point de terminaison. Cela nécessite que vous connaissiez vos services dépendants (les services que VOUS appelez) et leurs points de terminaison.
la source
Vous pouvez également vous référer à ce billet de blog de Simon Timms: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
la source
Une chose à souligner, qu'aucune des notes de blogs «ne pas utiliser en utilisant» est que ce ne sont pas seulement les BaseAddress et DefaultHeader que vous devez prendre en compte. Une fois que vous avez rendu HttpClient statique, il y a des états internes qui seront portés à travers les demandes. Un exemple: vous vous authentifiez auprès d'un tiers avec HttpClient pour obtenir un jeton FedAuth (ignorez pourquoi pas en utilisant OAuth / OWIN / etc), ce message de réponse a un en-tête Set-Cookie pour FedAuth, ceci est ajouté à votre état HttpClient. Le prochain utilisateur à se connecter à votre API enverra le cookie FedAuth de la dernière personne, sauf si vous gérez ces cookies à chaque demande.
la source
Comme premier problème, bien que cette classe soit jetable, son utilisation avec l'
using
instruction n'est pas le meilleur choix car même lorsque vous supprimez unHttpClient
objet, le socket sous-jacent n'est pas immédiatement libéré et peut provoquer un problème sérieux nommé `` épuisement des sockets ''.Mais il y a un deuxième problème
HttpClient
que vous pouvez rencontrer lorsque vous l'utilisez comme objet singleton ou statique. Dans ce cas, un singleton ou un statiqueHttpClient
ne respecte pas lesDNS
changements.dans .net core, vous pouvez faire la même chose avec HttpClientFactory quelque chose comme ceci:
Configurer les services
documentation et exemple sur ici
la source