Použití IHttpClientFactory k implementaci odolných požadavků HTTP
Tip
Tento obsah je výňatek z eBooku, architektury mikroslužeb .NET pro kontejnerizované aplikace .NET, které jsou k dispozici na .NET Docs nebo jako zdarma ke stažení PDF, které lze číst offline.
IHttpClientFactory je kontrakt implementovaný objektem DefaultHttpClientFactory
pro vytváření názorů, který je k dispozici od .NET Core 2.1 pro vytváření HttpClient instancí, které se mají použít ve vašich aplikacích.
Problémy s původní třídou HttpClient dostupnou v .NET
Původní a dobře známou HttpClient třídu lze snadno použít, ale v některých případech ji mnoho vývojářů správně nepoužívá.
Ačkoli tato třída implementuje IDisposable
, deklarování a vytvoření instance v rámci using
příkazu není upřednostňované, protože když HttpClient
se objekt odstraní, podkladový soket není okamžitě uvolněn, což může vést k problému vyčerpání soketu. Další informace o tomto problému najdete v blogovém příspěvku , který používáte httpClient, a je to nestabilita vašeho softwaru.
HttpClient
Proto je určen k vytvoření instance jednou a po celou dobu životnosti aplikace znovu použít. HttpClient
Vytvoření instance třídy pro každou žádost vyčerpá počet soketů dostupných při velkém zatížení. Výsledkem tohoto problému budou SocketException
chyby. Možné přístupy k vyřešení tohoto problému jsou založeny na vytvoření objektu HttpClient
jako singleton nebo statické, jak je vysvětleno v tomto článku Microsoftu o použití HttpClient. Může to být vhodné řešení pro krátkodobé konzolové aplikace nebo podobné, které běží několikrát denně.
Dalším problémem, na který narazí vývojáři, je použití sdílené instance dlouhotrvajících HttpClient
procesů. V situaci, kdy se HttpClient vytvoří instance jako jeden nebo statický objekt, se nepodaří zpracovat změny DNS, jak je popsáno v tomto problému úložiště GitHubu dotnet/runtime.
Tento problém ale ve skutečnosti HttpClient
není s každou sekundou, ale s výchozím konstruktorem pro HttpClient, protože vytvoří novou konkrétní instanci HttpMessageHandler, což je ten, který má vyčerpání soketů a problémy se změnami DNS uvedené výše.
Abychom vyřešili výše uvedené problémy a aby HttpClient
bylo možné spravovat instance, zavedla .NET Core 2.1 dva přístupy, z nichž jedna je IHttpClientFactory. Jedná se o rozhraní, které se používá ke konfiguraci a vytváření HttpClient
instancí v aplikaci prostřednictvím injektáže závislostí (DI). Poskytuje také rozšíření middlewaru založeného na Polly, která využívají delegování obslužných rutin v HttpClient.
Alternativou je použití SocketsHttpHandler
s nakonfigurovaným PooledConnectionLifetime
. Tento přístup se používá u dlouhotrvajících static
nebo singletonových HttpClient
instancí. Další informace o různých strategiích najdete v pokynech httpClient pro .NET.
Polly je knihovna pro zpracování přechodných chyb, která vývojářům pomáhá přidávat do svých aplikací odolnost pomocí některých předem definovaných zásad plynulým a bezpečným způsobem.
Výhody používání IHttpClientFactory
Současná implementace IHttpClientFactory, která také implementuje IHttpMessageHandlerFactory, nabízí následující výhody:
- Poskytuje centrální umístění pro pojmenování a konfiguraci logických
HttpClient
objektů. Můžete například nakonfigurovat klienta (agenta služby), který je předem nakonfigurovaný pro přístup ke konkrétní mikroslužbě. - Spoluvytvářet koncept odchozího middlewaru prostřednictvím delegování obslužných rutin v
HttpClient
middlewaru založeném na Polly a implementaci middlewaru založeného na Polly pro zajištění odolnosti. HttpClient
již má koncept delegování obslužných rutin, které by mohly být propojeny pro odchozí požadavky HTTP. Klienty HTTP můžete zaregistrovat do továrny a pomocí obslužné rutiny Polly můžete použít zásady Polly pro opakování, CircuitBreakers atd.- Spravujte životnost HttpMessageHandler , abyste se vyhnuli uvedeným problémům nebo problémům, ke kterým může dojít při správě
HttpClient
životního cyklu sami.
Tip
Instance HttpClient
vložené pomocí DI je možné bezpečně odstranit, protože přidružené HttpMessageHandler
je spravováno továrnou. Vložené HttpClient
instance jsou přechodné z hlediska DI, zatímco HttpMessageHandler
instance mohou být považovány za Scoped. HttpMessageHandler
instance mají vlastní obory DI, oddělené od oborů aplikace (například ASP.NET rozsahy příchozích požadavků). Další informace naleznete v tématu Použití HttpClientFactory v .NET.
Poznámka:
Implementace IHttpClientFactory
(DefaultHttpClientFactory
) je úzce svázaná s implementací DI v Microsoft.Extensions.DependencyInjection
balíčku NuGet. Pokud potřebujete použít HttpClient
bez DI nebo s jinýmiimplementacemi static
HttpClient
PooledConnectionLifetime
Další informace najdete v tématu HttpClient guidelines for .NET.
Několik způsobů použití IHttpClientFactory
Ve své aplikaci můžete použít IHttpClientFactory
několik způsobů:
- Základní použití
- Použití pojmenovaných klientů
- Použití typed clients
- Použití vygenerovaných klientů
V zájmu stručnosti ukazuje tento návod nejstrukturovanější způsob použití IHttpClientFactory
, což je použití typed clients (model agenta služby). Všechny možnosti jsou však zdokumentované a v současné době jsou uvedeny v tomto článku, který se zabývá používánímIHttpClientFactory
.
Poznámka:
Pokud vaše aplikace vyžaduje soubory cookie, může být lepší se vyhnout použití IHttpClientFactory ve vaší aplikaci. Alternativní způsoby správy klientů najdete v pokynech pro používání klientů HTTP.
Použití typed clients with IHttpClientFactory
Co je tedy "Typový klient"? Je to jenom HttpClient
předem nakonfigurovaná pro určité použití. Tato konfigurace může zahrnovat konkrétní hodnoty, jako je základní server, hlavičky HTTP nebo vypršení časového limitu.
Následující diagram znázorňuje, jak se používají IHttpClientFactory
typoví klienti:
Obrázek 8–4 Použití IHttpClientFactory
s typed client třídy.
Na obrázku ClientService
výše používá HttpClient
kód (používaný kontrolerem nebo kódem klienta) vytvořený registrovaným IHttpClientFactory
kódem . Tato továrna HttpMessageHandler
přiřadí z fondu k objektu HttpClient
. Lze HttpClient
nakonfigurovat pomocí zásad Polly při registraci IHttpClientFactory
v kontejneru DI pomocí metody AddHttpClientrozšíření .
Pokud chcete nakonfigurovat výše uvedenou strukturu, přidejte IHttpClientFactory do aplikace instalaci Microsoft.Extensions.Http
balíčku NuGet, který obsahuje metodu AddHttpClient rozšíření pro IServiceCollection. Tato metoda rozšíření zaregistruje interní DefaultHttpClientFactory
třídu, která se má použít jako jednoúčelové rozhraní IHttpClientFactory
. Definuje přechodnou konfiguraci pro HttpMessageHandlerBuilder. Tato obslužná rutina zprávy (HttpMessageHandler objekt), převzatá z fondu, je používána vrácenou HttpClient
z továrny.
V dalším fragmentu kódu můžete zjistit, jak AddHttpClient()
se dá použít k registraci klientů typu (agentů služeb), které potřebují používat HttpClient
.
// Program.cs
//Add http client services at ConfigureServices(IServiceCollection services)
builder.Services.AddHttpClient<ICatalogService, CatalogService>();
builder.Services.AddHttpClient<IBasketService, BasketService>();
builder.Services.AddHttpClient<IOrderingService, OrderingService>();
Registrace klientských služeb, jak je znázorněno v předchozím fragmentu kódu, vytvoří DefaultClientFactory
pro každou službu standard HttpClient
. Zadaný klient je zaregistrovaný jako přechodný v kontejneru DI. V předchozím kódu AddHttpClient()
zaregistruje CatalogService, BasketService, OrderingService jako přechodné služby, aby je bylo možné vkládat a využívat přímo bez nutnosti dalších registrací.
Do registrace můžete přidat také konfiguraci specifickou pro instanci, například ke konfiguraci základní adresy a přidání některých zásad odolnosti, jak je znázorněno v následujících příkladech:
builder.Services.AddHttpClient<ICatalogService, CatalogService>(client =>
{
client.BaseAddress = new Uri(builder.Configuration["BaseUrl"]);
})
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
V tomto dalším příkladu uvidíte konfiguraci jedné z výše uvedených zásad:
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
Další podrobnosti o používání Polly najdete v dalším článku.
Životnosti HttpClient
Pokaždé, když získáte objekt z objektu HttpClient
IHttpClientFactory
, je vrácena nová instance. Každý z nich HttpClient
ale používá fond HttpMessageHandler
, který se používá IHttpClientFactory
k omezení spotřeby prostředků, pokud HttpMessageHandler
nevypršela platnost životnosti.
Sdružování obslužných rutin je žádoucí, protože každá obslužná rutina obvykle spravuje vlastní základní připojení HTTP; vytváření více obslužných rutin, než je nutné, může vést ke zpoždění připojení. Některé obslužné rutiny také trvale udržují připojení otevřená, což může obslužné rutině zabránit v reakci na změny DNS.
Objekty HttpMessageHandler
ve fondu mají životnost, která je doba HttpMessageHandler
, po kterou může být instance ve fondu znovu použita. Výchozí hodnota je dvě minuty, ale lze ji přepsat na typ klienta. Pokud ho chcete přepsat, zavolejte SetHandlerLifetime()
IHttpClientBuilder vrácené při vytváření klienta, jak je znázorněno v následujícím kódu:
//Set 5 min as the lifetime for the HttpMessageHandler objects in the pool used for the Catalog Typed Client
builder.Services.AddHttpClient<ICatalogService, CatalogService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Každý typový klient může mít svou vlastní nakonfigurovanou hodnotu životnosti obslužné rutiny. Nastavte životnost tak, aby InfiniteTimeSpan
se zakázala vypršení platnosti obslužné rutiny.
Implementace typed client tříd, které používají vložené a nakonfigurované HttpClient
Jako předchozí krok musíte mít definované třídy typed client, například třídy v ukázkovém kódu, jako je BasketService, CatalogService, OrderingService atd. – Typed Client je třída, která přijímá HttpClient
objekt (vložený prostřednictvím jeho konstruktoru) a používá ho k volání některé vzdálené služby HTTP. Příklad:
public class CatalogService : ICatalogService
{
private readonly HttpClient _httpClient;
private readonly string _remoteServiceBaseUrl;
public CatalogService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Catalog> GetCatalogItems(int page, int take,
int? brand, int? type)
{
var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl,
page, take, brand, type);
var responseString = await _httpClient.GetStringAsync(uri);
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
return catalog;
}
}
Typed Client (CatalogService
v příkladu) je aktivován di (injektáž závislostí), což znamená, že může přijmout jakoukoli registrovanou službu v jeho konstruktoru, kromě HttpClient
.
Typový klient je v podstatě přechodný objekt, což znamená, že se vytvoří nová instance pokaždé, když je potřeba. Při každém vytvoření obdrží novou HttpClient
instanci. HttpMessageHandler
Objekty ve fondu jsou však objekty, které jsou opakovaně používány více HttpClient
instancemi.
Použití tříd typed client
A konečně, jakmile máte zapsaných tříd implementované, můžete je zaregistrovat a nakonfigurovat s AddHttpClient()
. Potom je můžete použít všude, kde jsou služby vloženy pomocí DI, například v kódu stránky Razor nebo kontroleru webové aplikace MVC, jak je znázorněno v následujícím kódu z eShopOnContainers:
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
public class CatalogController : Controller
{
private ICatalogService _catalogSvc;
public CatalogController(ICatalogService catalogSvc) =>
_catalogSvc = catalogSvc;
public async Task<IActionResult> Index(int? BrandFilterApplied,
int? TypesFilterApplied,
int? page,
[FromQuery]string errorMsg)
{
var itemsPage = 10;
var catalog = await _catalogSvc.GetCatalogItems(page ?? 0,
itemsPage,
BrandFilterApplied,
TypesFilterApplied);
//… Additional code
}
}
}
Až do tohoto okamžiku výše uvedený fragment kódu ukazuje pouze příklad provádění běžných požadavků HTTP. "Magie" ale přichází v následujících částech, kde ukazuje, jak všechny požadavky HTTP vytvořené HttpClient
pomocí odolných zásad, jako jsou opakování s exponenciálním zpoplatněním, jističem, funkcemi zabezpečení pomocí ověřovacích tokenů nebo dokonce jakoukoli jinou vlastní funkcí. A všechny tyto kroky je možné provést pouze přidáním zásad a delegováním obslužných rutin do registrovaných typed klientů.
Další materiály
Pokyny pro HttpClient pro .NET
https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelinesPoužití HttpClientFactory v .NET
https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factoryPoužití HttpClientFactory v ASP.NET Core
https://learn.microsoft.com/aspnet/core/fundamentals/http-requestsZdrojový kód HttpClientFactory v
dotnet/runtime
úložišti GitHub
https://github.com/dotnet/runtime/tree/release/7.0/src/libraries/Microsoft.Extensions.Http/Polly (odolnost rozhraní .NET a knihovna zpracování přechodných chyb)
https://thepollyproject.azurewebsites.net/