Použití IHttpClientFactory k implementaci odolných požadavků HTTP
Spropitné
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ý službou DefaultHttpClientFactory
, objektem pro vytváření instancí, které se mají používat ve vašich aplikacích, protože .NET Core 2.1 je k dispozici pro vytváření instancí HttpClient.
Problémy s původní třídou HttpClient dostupnou v .NET
Původní a dobře známé HttpClient třídy lze snadno použít, ale v některých případech ji mnoho vývojářů správně nepoužívá.
I když tato třída implementuje IDisposable
, deklarování a instanci v rámci příkazu using
není doporučeno, protože při odstranění objektu HttpClient
není podkladový soket okamžitě uvolněn, což může vést k problému s vyčerpáním soketu . Další informace o tomto problému najdete v blogovém příspěvku Používáte HttpClient špatně a je to nestabilita vašeho softwaru.
Proto je HttpClient
určeno k instanciaci jednou a opětovnému využití v průběhu životnosti aplikace. Vytvoření instance třídy HttpClient
pro každý požadavek vyčerpá počet soketů dostupných při velkém zatížení. Tento problém bude mít za následek chyby SocketException
. Možné přístupy k vyřešení tohoto problému jsou založeny na vytvoření objektu HttpClient
jako singleton nebo statické proměnné, jak je vysvětleno v tomto článku Microsoft o použití HttpClientu. 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 HttpClient
v dlouhotrvajících procesech. V situaci, kdy je HttpClient vytvořen jako instance singletonu nebo statický objekt, nezvládne zpracovat změny DNS, jak je popsáno v této záležitosti úložiště GitHub dotnet/runtime.
Tento problém ale ve skutečnosti není HttpClient
za sekundu, ale s výchozím konstruktorem proHttpClient, protože vytvoří novou konkrétní instanci HttpMessageHandler, což je ten, který má sokety vyčerpání a problémy se změnami DNS uvedené výše.
Abychom vyřešili výše uvedené problémy a aby HttpClient
instance byly spravovatelné, zavedla platforma .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í instancí HttpClient
v aplikaci prostřednictvím injektáže závislostí (DI). Poskytuje také rozšíření pro middleware založený na Polly, které umožňuje využití delegujících obslužných rutin v HttpClient.
Alternativou je použití SocketsHttpHandler
s nakonfigurovaným PooledConnectionLifetime
. Tento přístup se používá u dlouhodobých instancí static
nebo instancí typu singleton HttpClient
. Další informace o různých strategiích najdete v tématu pokyny 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
Aktuální 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ě. - Formalizujte koncept odchozího middlewaru delegováním obslužných rutin v
HttpClient
a implementací middlewaru založeného na Polly, abyste mohli využít politiky Polly pro zvýšení 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 opětovné pokusy, přerušovače okruhů atd. - Spravujte životnost HttpMessageHandler, abyste se vyhnuli uvedeným problémům, které mohou nastat při vlastní správě životnosti
HttpClient
.
Spropitné
Instance HttpClient
vložené pomocí DI je možné bezpečně likvidovat, protože související HttpMessageHandler
spravuje továrna. Vložené HttpClient
instance jsou Přechodné z pohledu závislosti, zatímco HttpMessageHandler
instance lze považovat za vymezené.
HttpMessageHandler
instance mají vlastní obory DI, oddělené od oborů aplikace (například rozsahy příchozích požadavků v ASP.NET). Další informace naleznete v tématu Použití HttpClientFactory v .NET.
Poznámka
Implementace IHttpClientFactory
(DefaultHttpClientFactory
) je úzce svázaná s implementací DI v balíčku NuGet Microsoft.Extensions.DependencyInjection
. Pokud potřebujete použít HttpClient
bez DI nebo s jinými implementacemi DI, zvažte použití static
nebo singletonu HttpClient
s nastaveným PooledConnectionLifetime
. Další informace najdete v tématu pokyny HttpClient pro .NET.
Několik způsobů použití IHttpClientFactory
V aplikaci můžete použít IHttpClientFactory
několika způsoby:
- Základní využití
- Použití pojmenovaných klientů
- Použití typovaných klientů
- Použití vygenerovaných klientů
V zájmu stručnosti tento návod ukazuje nejstrukturovanější způsob používání IHttpClientFactory
, což je použití typovaných klientů (vzorec agenta služby). Všechny možnosti jsou však zdokumentované a jsou nyní uvedeny v tomto článku, který se zabývá IHttpClientFactory
využitím.
Poznámka
Pokud vaše aplikace vyžaduje soubory cookie, může být lepší se vyhnout používání IHttpClientFactory ve vaší aplikaci. Alternativní způsoby správy klientů najdete v tématu Pokyny pro používání klientů HTTP.
Jak používat typované klienty s IHttpClientFactory
Co je tedy "Typový klient"? Je to jen HttpClient
, která je 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 použití typových klientů s IHttpClientFactory
:
obrázek 8–4. Použití IHttpClientFactory
s třídami typizovaného klienta.
Na obrázku výše používá ClientService
(používaný kontrolerem nebo kódem klienta) HttpClient
vytvořené registrovaným IHttpClientFactory
. Tato továrna přiřadí HttpMessageHandler
z fondu k HttpClient
.
HttpClient
lze nakonfigurovat pomocí zásad Polly při registraci IHttpClientFactory
v kontejneru DI pomocí metody rozšíření AddHttpClient.
Pokud chcete nakonfigurovat výše uvedenou strukturu, přidejte do aplikace IHttpClientFactory instalací balíčku NuGet Microsoft.Extensions.Http
, který obsahuje metodu rozšíření AddHttpClient pro IServiceCollection. Tato metoda rozšíření zaregistruje třídu DefaultHttpClientFactory
interní, která bude použita jako singleton pro rozhraní IHttpClientFactory
. Definuje přechodnou konfiguraci pro HttpMessageHandlerBuilder. Tuto obslužnou rutinu zprávy (HttpMessageHandler objekt), převzatou z fondu, používá HttpClient
, která byla vrácena z továrny.
V dalším úryvku zjistíte, jak lze AddHttpClient()
použít k registraci typovaných klientů (Service Agents), kteří 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>();
Registrací klientských služeb, jak je znázorněno v předchozím fragmentu kódu, vytvoří DefaultClientFactory
pro každou službu standardní HttpClient
. Zadaný klient je zaregistrovaný jako přechodný v kontejneru DI. V předchozím kódu registruje AddHttpClient()
, CatalogService, BasketService, OrderingService jako přechodné služby, aby mohly být vloženy a používány přímo, a to 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žití Polly najdete v příštím článku.
Životnost HttpClient
Pokaždé, když z IHttpClientFactory
získáte objekt HttpClient
, vrátí se nová instance. Každý HttpClient
ale používá HttpMessageHandler
, který je ve fondu a znovu používán IHttpClientFactory
, aby se snížila spotřeba prostředků, dokud nevypršela platnost životnosti HttpMessageHandler
.
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í dobu životnosti, po kterou lze opakovaně použít instanci HttpMessageHandler
ve fondu. Výchozí hodnota je dvě minuty, ale může být upravena pro jednotlivé typy klientů. Pokud chcete nastavení přepsat, zavolejte SetHandlerLifetime()
na IHttpClientBuilder, který je vrácen při vytváření klienta, jak ukazuje následující kód:
//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ý typizovaný klient může disponovat vlastní nakonfigurovanou hodnotou životnosti obslužné rutiny. Nastavte životnost na InfiniteTimeSpan
pro deaktivaci vypršení platnosti obslužné rutiny.
Implementujte své třídy Typed Client, které používají vložený a nakonfigurovaný HttpClient
Jako předchozí krok musíte mít definované třídy typed client, jako jsou třídy v ukázkovém kódu, jako je BasketService, CatalogService, OrderingService atd. – Typový klient je třída, která přijímá objekt HttpClient
(vložený prostřednictvím jeho konstruktoru) a používá ho k volání některé vzdálené služby HTTP. Napří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 (injektování závislostí), což znamená, že může přijmout jakoukoli registrovanou službu ve svém konstruktoru, včetně 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í instance obdrží novou instanci HttpClient
. Objekty HttpMessageHandler
ve fondu jsou však ty, které jsou používány opakovaně více instancemi HttpClient
.
Použijte své třídy Typed Client
A konečně, jakmile máte implementované zapsané třídy, 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
můžou mít odolné zásady, jako jsou opakování s exponenciálním zpožděním, obvodové přerušovače, bezpečnostní funkce využívající ověřovací tokeny nebo dokonce jakékoli jiné vlastní funkce. A všechny tyto kroky je možné jednoduše provést přidáním zásad a delegováním obslužných rutin do registrovaných typovaných klientů.
Další zdroje informací
Pokyny HttpClient pro .NEThttps://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines
Použití HttpClientFactory v rozhraní .NEThttps://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory
Použití HttpClientFactory v ASP.NET Corehttps://learn.microsoft.com/aspnet/core/fundamentals/http-requests
zdrojový kód HttpClientFactory v úložišti
dotnet/runtime
GitHubuhttps://github.com/dotnet/runtime/tree/release/7.0/src/libraries/Microsoft.Extensions.Http/Polly (odolnost rozhraní .NET a knihovna pro zpracování přechodných chyb)https://thepollyproject.azurewebsites.net/