Rugalmas HTTP-kérések implementálása az IHttpClientFactory használatával
Tipp.
Ez a tartalom egy részlet a .NET-alkalmazásokhoz készült .NET-alkalmazásokhoz készült eBook, .NET Microservices Architecture című eBookból, amely elérhető a .NET Docs-on vagy egy ingyenesen letölthető PDF-fájlként, amely offline módban is olvasható.
IHttpClientFactory a .NET Core 2.1 óta elérhető , véleményezett gyár által DefaultHttpClientFactory
megvalósított szerződés, amely az alkalmazásokban használandó példányok létrehozására HttpClient szolgál.
A .NET-ben elérhető eredeti HttpClient-osztálysal kapcsolatos problémák
Az eredeti és jól ismert HttpClient osztály könnyen használható, de bizonyos esetekben sok fejlesztő nem használja megfelelően.
Bár ez az osztály implementálja IDisposable
, deklarálja és példányosítja azt egy using
utasításon belül, nem ajánlott, mert amikor az HttpClient
objektumot megsemmisítik, a mögöttes szoftvercsatorna nem szabadul fel azonnal, ami szoftvercsatornák kimerüléséhez vezethet. A problémáról további információt a HttpClient helytelen használata és a szoftver destabilizálása című blogbejegyzésben talál.
Ezért azt tervezik, HttpClient
hogy egyszer példányosítják, és az alkalmazás teljes élettartama alatt újra felhasználják. Az osztály minden kéréshez való példányosítása HttpClient
kimeríti a nagy terhelés alatt elérhető foglalatok számát. Ez a probléma hibákat fog eredményezni SocketException
. A probléma megoldásának lehetséges módjai az HttpClient
objektum önálló vagy statikus létrehozásán alapulnak, amint azt a HttpClient-használatról szóló Microsoft-cikk ismerteti. Ez jó megoldás lehet olyan rövid élettartamú konzolalkalmazásokhoz vagy hasonlókhoz, amelyek naponta néhányszor futnak.
Egy másik probléma, amelybe a fejlesztők belefutnak, a hosszú ideig futó folyamatok megosztott példányának HttpClient
használata. Ha a HttpClient példányosítása egyetlen vagy statikus objektumként történik, nem kezeli a dotnet/runtime GitHub-adattár jelen problémájában leírt DNS-módosításokat.
A probléma azonban nem önmagában HttpClient
van, hanem a HttpClient alapértelmezett konstruktorával, mivel egy új konkrét példányt hoz létre, amely a szoftvercsatornák kimerülésével HttpMessageHandler és a DNS-módosításokkal kapcsolatos fent említett problémákat tartalmazza.
A fent említett problémák megoldása és a példányok kezelhetővé tétele HttpClient
érdekében a .NET Core 2.1 két megközelítést vezetett be, amelyek közül az egyik a IHttpClientFactory. Ez egy felület, amellyel konfigurálhatók és hozhatók létre HttpClient
példányok egy alkalmazásban a Dependency Injection (DI) használatával. Emellett a Polly-alapú köztes szoftver bővítményeit is biztosítja, hogy kihasználhassa a HttpClient kezelőinek delegálását.
A másik lehetőség a SocketsHttpHandler
konfigurált PooledConnectionLifetime
. Ez a megközelítés hosszú élettartamú vagy static
egypéldányos HttpClient
példányokra vonatkozik. A különböző stratégiákról további információt a .NET httpClient-irányelvei című témakörben talál.
A Polly egy átmeneti hibakezelési kódtár, amely segít a fejlesztőknek rugalmasságot adni az alkalmazásaikhoz bizonyos előre meghatározott szabályzatok folyékony és szálbiztos használatával.
Az IHttpClientFactory használatának előnyei
A jelenlegi implementáció a IHttpClientFactorykövetkező előnyöket nyújtja IHttpMessageHandlerFactory:
- Központi helyet biztosít a logikai
HttpClient
objektumok elnevezéséhez és konfigurálásához. Konfigurálhat például egy olyan ügyfelet (szolgáltatásügynököt), amely előre konfigurálva van egy adott mikroszolgáltatás eléréséhez. - Kodifikálja a kimenő köztes szoftver fogalmát a Polly-alapú köztes szoftver kezelőinek
HttpClient
delegálásával és implementálásával, hogy kihasználhassa a Polly rugalmasságra vonatkozó szabályzatait. HttpClient
már rendelkezik a kimenő HTTP-kérésekhez összekapcsolható kezelők delegálásának fogalmával. HTTP-ügyfeleket regisztrálhat a gyárban, és Polly-kezelővel Polly-szabályzatokat használhat az Újrapróbálkozáshoz, a CircuitBreakershez és így tovább.- Kezelheti az élettartamot HttpMessageHandler , hogy elkerülje azokat a problémákat/problémákat, amelyek az élettartamok kezelésekor
HttpClient
fordulhatnak elő.
Tipp.
A HttpClient
DI által injektált példányok biztonságosan megsemmisíthetők, mivel a társított HttpMessageHandler
példányokat a gyár kezeli. Az injektált HttpClient
példányok a DI szempontjából átmenetiek, míg HttpMessageHandler
a példányok hatókörrel rendelkezőnek tekinthetők. HttpMessageHandler
a példányok saját DI-hatókörrel rendelkeznek, az alkalmazás hatókörétől ( például ASP.NET bejövő kérelem hatóköreitől). További információ: HttpClientFactory használata a .NET-ben.
Feljegyzés
A () megvalósítása IHttpClientFactory
szorosan kapcsolódik a NuGet-csomag DI-implementációjáhozMicrosoft.Extensions.DependencyInjection
.DefaultHttpClientFactory
Ha di nélkül vagy más DI-implementációkkal kell használnia HttpClient
, fontolja meg egy vagy egyetlentonn static
HttpClient
használatát a beállítással PooledConnectionLifetime
. További információ: HttpClient irányelvek a .NET-hez.
Az IHttpClientFactory használatának több módja
Az alkalmazásban többféleképpen is használhatja IHttpClientFactory
:
- Alapszintű használat
- Névvel ellátott ügyfelek használata
- Beírt ügyfelek használata
- Generált ügyfelek használata
A rövidség kedvéért ez az útmutató bemutatja a leginkább strukturált felhasználási IHttpClientFactory
módot, azaz a típusos ügyfelek (szolgáltatásügynök-minta) használatát. Az összes lehetőség azonban dokumentálva van, és jelenleg a használatról szóló IHttpClientFactory
cikkben szerepel.
Feljegyzés
Ha az alkalmazás cookie-kat igényel, érdemes lehet elkerülni a használatot IHttpClientFactory az alkalmazásban. Az ügyfelek kezelésének alternatív módjaiért tekintse meg a HTTP-ügyfelek használatának irányelveit
Gépelt ügyfelek használata az IHttpClientFactory használatával
Szóval, mi az a "Gépelt ügyfél"? Ez csak egy HttpClient
előre konfigurált bizonyos használatra. Ez a konfiguráció bizonyos értékeket tartalmazhat, például az alapkiszolgálót, a HTTP-fejléceket vagy az időtúllépéseket.
Az alábbi ábra bemutatja, hogyan használják a gépelt ügyfeleket IHttpClientFactory
:
8-4. ábra. Használat IHttpClientFactory
gépelt ügyfélosztályokkal.
A fenti képen egy ClientService
(vezérlő vagy ügyfélkód által használt) a regisztrált IHttpClientFactory
felhasználó által létrehozott kódot használjaHttpClient
. Ez a gyár hozzárendel egy HttpMessageHandler
készletet a HttpClient
. A HttpClient
Lekérdezési szabályzatokkal konfigurálható, amikor a DI-tárolóban regisztrálja a IHttpClientFactory
bővítménymetódussal AddHttpClient.
A fenti struktúra konfigurálásához adja hozzá IHttpClientFactory az alkalmazáshoz a Microsoft.Extensions.Http
bővítménymetódust IServiceCollectiontartalmazó AddHttpClient NuGet-csomagot. Ez a bővítménymetódus regisztrálja a belső DefaultHttpClientFactory
osztályt, amelyet egyetlentonként kell használni az interfészhez IHttpClientFactory
. Átmeneti konfigurációt határoz meg a HttpMessageHandlerBuilder. A készletből származó üzenetkezelőt (HttpMessageHandler objektumot) a HttpClient
gyári visszaadott használja.
A következő kódrészletben láthatja, hogyan AddHttpClient()
regisztrálhatók a használni HttpClient
kívánt típusú ügyfelek (szolgáltatásügynökök).
// 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>();
Az ügyfélszolgáltatások regisztrálása az előző kódrészletben látható módon minden szolgáltatáshoz szabványossá HttpClient
teszi a DefaultClientFactory
létrehozást. A beírt ügyfél átmenetiként van regisztrálva a DI-tárolóban. Az előző kódban AddHttpClient()
a CatalogService, a BasketService, az OrderingService szolgáltatást átmeneti szolgáltatásként regisztrálja, hogy közvetlenül, további regisztrációk nélkül lehessen injektálni és felhasználni őket.
A regisztrációban a példányspecifikus konfigurációt is hozzáadhatja például az alapcím konfigurálásához, és hozzáadhat néhány rugalmassági szabályzatot, ahogy az alábbi ábrán látható:
builder.Services.AddHttpClient<ICatalogService, CatalogService>(client =>
{
client.BaseAddress = new Uri(builder.Configuration["BaseUrl"]);
})
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
Ebben a következő példában a fenti szabályzatok egyikének konfigurációját láthatja:
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
A Polly használatával kapcsolatos további részleteket a Következő cikkben talál.
HttpClient-élettartamok
Minden alkalommal, amikor egy objektumot HttpClient
kap a IHttpClientFactory
rendszer, egy új példányt ad vissza. De mindegyik HttpClient
egy HttpMessageHandler
készletezett és újrahasznált erőforrás-felhasználást IHttpClientFactory
használ az erőforrás-felhasználás csökkentése érdekében, feltéve, hogy az HttpMessageHandler
élettartam még nem járt le.
A kezelők készletezése kívánatos, mivel az egyes kezelők általában saját mögöttes HTTP-kapcsolatokat kezelnek; a szükségesnél több kezelő létrehozása kapcsolati késéseket eredményezhet. Egyes kezelők korlátlan ideig nyitva tartják a kapcsolatokat, ami megakadályozhatja, hogy a kezelő reagáljon a DNS-változásokra.
A HttpMessageHandler
készletben lévő objektumok élettartama az a időtartam, amely alatt a készlet egy HttpMessageHandler
példánya újra felhasználható. Az alapértelmezett érték két perc, de felül lehet bírálni gépelt ügyfélenként. A felülbíráláshoz hívja meg SetHandlerLifetime()
az IHttpClientBuilder ügyfél létrehozásakor visszaadott hívást az alábbi kódban látható módon:
//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));
Minden gépelt ügyfél saját konfigurált kezelő élettartam-értékkel rendelkezhet. Állítsa be az élettartamot a InfiniteTimeSpan
kezelő lejáratának letiltásához.
Az injektált és konfigurált HttpClientet használó gépelt ügyfélosztályok implementálása
Előző lépésként definiálnia kell a beírt ügyfélosztályokat, például a mintakódban szereplő osztályokat, például a "BasketService", a "CatalogService", az "OrderingService" stb. osztályt. A gépelt ügyfél egy olyan osztály, amely elfogad egy HttpClient
objektumot (a konstruktoron keresztül injektálva), és arra használja, hogy meghívjon egy távoli HTTP-szolgáltatást. Példa:
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;
}
}
A gépelt ügyfelet (CatalogService
a példában) a DI (Dependency Injection) aktiválja, ami azt jelenti, hogy a konstruktorban bármilyen regisztrált szolgáltatást elfogadhat a konstruktoron kívül HttpClient
.
A gépelt ügyfél tulajdonképpen átmeneti objektum, ami azt jelenti, hogy minden alkalommal létrejön egy új példány, amikor szükség van rá. Minden egyes létrehozásakor új HttpClient
példányt kap. A HttpMessageHandler
készletben lévő objektumok azonban azok az objektumok, amelyeket több HttpClient
példány is újra felhasznál.
A gépelt ügyfélosztályok használata
Végül, miután implementálta a gépelt osztályokat, regisztrálhatja és konfigurálhatja AddHttpClient()
őket. Ezt követően bárhol használhatja őket, ahol a DI szolgáltatásokat injektálja, például a Razor oldalkódjában vagy egy MVC webalkalmazás-vezérlőben, amely az alábbi eShopOnContainers-kódban látható:
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
}
}
}
Eddig a pontig a fenti kódrészlet csak a szokásos HTTP-kérések végrehajtására szolgáló példát mutatja. A "varázslat" azonban a következő szakaszokban jelenik meg, ahol bemutatja, hogy az összes HTTP-kérés rugalmas HttpClient
szabályzatokkal rendelkezhet, például exponenciális visszakapcsolással végzett újrapróbálkozások, megszakítók, hitelesítési jogkivonatokat használó biztonsági funkciók vagy akár bármilyen más egyéni funkció. Mindez pedig csak úgy végezhető el, ha szabályzatokat ad hozzá, és kezelőket delegál a regisztrált gépelt ügyfelekhez.
További erőforrások
HttpClient-irányelvek a .NET-hez
https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelinesA HttpClientFactory használata a .NET-ben
https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factoryA HttpClientFactory használata a ASP.NET Core-ban
https://learn.microsoft.com/aspnet/core/fundamentals/http-requestsHttpClientFactory forráskód a
dotnet/runtime
GitHub-adattárban
https://github.com/dotnet/runtime/tree/release/7.0/src/libraries/Microsoft.Extensions.Http/Polly (.NET rugalmasság és átmeneti hibakezelési kódtár)
https://thepollyproject.azurewebsites.net/
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: