Gunakan IHttpClientFactory untuk menerapkan permintaan yang tangguh
Tip
Konten ini adalah kutipan dari eBook, .NET Microservices Architecture for Containerized .NET Applications, tersedia di .NET Docs atau sebagai PDF yang dapat diunduh gratis dan dapat dibaca secara offline.
IHttpClientFactory adalah kontrak yang diimplementasikan oleh DefaultHttpClientFactory
, pabrik dogmatis, tersedia sejak .NET Core 2.1, untuk membuat instans HttpClient yang akan digunakan dalam aplikasi Anda.
Masalah dengan kelas HttpClient asli yang tersedia di .NET
Kelas HttpClient asli dan dikenal dapat dengan mudah digunakan, tetapi dalam beberapa kasus, kelas tersebut tidak digunakan dengan benar oleh banyak pengembang.
Meskipun kelas ini mengimplementasikan IDisposable
, mendeklarasikan dan membuat instansnya dalam using
pernyataan tidak disukai karena ketika objek HttpClient
dibuang, soket yang mendasarinya tidak segera dirilis, ini dapat menyebabkan masalah soket hampir habis. Untuk informasi selengkapnya tentang masalah ini, lihat postingan blog Anda salah menggunakan HttpClient dan membuat perangkat lunak Anda tidak stabil.
Oleh karena itu, HttpClient
dimaksudkan untuk dipakai sekali, kemudian digunakan kembali sepanjang masa pakai aplikasi. Membuat instans kelas HttpClient
untuk setiap permintaan akan menghabiskan jumlah soket yang tersedia di bawah beban berat. Masalah tersebut akan mengakibatkan kesalahan SocketException
. Kemungkinan pendekatan untuk memecahkan masalah itu didasarkan pada pembuatan objek HttpClient
sebagai tunggal atau statis, seperti yang dijelaskan dalam artikel Microsoft ini tentang penggunaan HttpClient. Ini bisa menjadi solusi yang baik untuk aplikasi konsol berumur pendek atau serupa, yang berjalan beberapa kali sehari.
Masalah lain yang dihadapi pengembang adalah saat menggunakan instans HttpClient
bersama dalam proses yang berjalan lama. Dalam situasi di mana HttpClient dibuat sebagai singleton atau objek statis, httpClient gagal menangani perubahan DNS seperti yang dijelaskan dalam masalah repositori GitHub dotnet/runtime ini.
Namun, masalahnya tidak benar-benar dengan HttpClient
per se, tetapi dengan konstruktor default untuk HttpClient, karena menciptakan instans konkret baru, HttpMessageHandleryang merupakan salah satu yang memiliki masalah soket hampir habis dan perubahan DNS yang disebutkan di atas.
Untuk mengatasi masalah yang disebutkan di atas dan untuk membuat HttpClient
instans dapat dikelola, .NET Core 2.1 memperkenalkan dua pendekatan, salah satunya adalah IHttpClientFactory. Ini adalah antarmuka yang digunakan untuk mengonfigurasi dan membuat HttpClient
instans di aplikasi melalui Dependency Injection (DI). Ini juga menyediakan ekstensi untuk middleware berbasis Polly untuk memanfaatkan pendelegasian penanganan di HttpClient.
Alternatifnya adalah menggunakan SocketsHttpHandler
dengan dikonfigurasi PooledConnectionLifetime
. Pendekatan ini diterapkan pada instans berumur panjang, static
atau singleton HttpClient
. Untuk mempelajari selengkapnya tentang strategi yang berbeda, lihat Panduan HttpClient untuk .NET.
Polly adalah pustaka penanganan kesalahan sementara yang membantu pengembang menambahkan ketahanan ke aplikasi mereka, dengan menggunakan beberapa kebijakan yang telah ditentukan sebelumnya dengan cara yang lancar dan aman.
Manfaat menggunakan IHttpClientFactory
Implementasi saat ini dari IHttpClientFactory, yang juga mengimplementasikan IHttpMessageHandlerFactory, memberikan manfaat berikut:
- Menyediakan lokasi pusat untuk penamaan dan konfigurasi objek
HttpClient
logis. Misalnya, Anda dapat mengonfigurasi klien (Agen Layanan) yang telah dikonfigurasi sebelumnya untuk mengakses layanan mikro tertentu. - Mengodifikasi konsep middleware keluar melalui pendelegasian penanganan di
HttpClient
dan mengimplementasikan middleware berbasis Polly untuk memanfaatkan kebijakan Polly untuk ketahanan. HttpClient
sudah memiliki konsep mendelegasikan penanganan yang dapat ditautkan bersama untuk permintaan HTTP keluar. Anda dapat mendaftarkan klien HTTP ke pabrik dan Anda dapat menggunakan pengendali Polly untuk menggunakan kebijakan Polly untuk Coba Lagi, Pemutus Sirkuit, dan sebagainya.- Kelola masa pakai HttpMessageHandler untuk menghindari masalah/masalah yang disebutkan yang dapat terjadi saat mengelola masa pakai
HttpClient
sendiri.
Tip
Instans HttpClient
yang disuntikkan oleh DI dapat dibuang dengan aman, karena yang terkait HttpMessageHandler
dikelola oleh pabrik. Instans yang disuntikkan HttpClient
bersifat Sementara dari perspektif DI, sementara HttpMessageHandler
instans dapat dianggap sebagai Cakupan. HttpMessageHandler
instans memiliki cakupan DI mereka sendiri, terpisah dari cakupan aplikasi (misalnya, ASP.NET cakupan permintaan masuk). Untuk informasi selengkapnya, lihat Menggunakan HttpClientFactory di .NET.
Catatan
Implementasi IHttpClientFactory
(DefaultHttpClientFactory
) terkait erat dengan implementasi DI dalam paket NuGet Microsoft.Extensions.DependencyInjection
. Jika Anda perlu menggunakan HttpClient
tanpa DI atau dengan implementasi DI lainnya, pertimbangkan untuk menggunakan static
atau singleton HttpClient
dengan PooledConnectionLifetime
penyiapan. Untuk informasi selengkapnya, lihat Panduan HttpClient untuk .NET.
Beberapa cara untuk menggunakan IHttpClientFactory
Ada beberapa cara yang dapat Anda gunakan IHttpClientFactory
dalam aplikasi Anda:
- Penggunaan dasar
- Gunakan Klien Bernama
- Gunakan Klien Berjenis
- Gunakan Klien yang Dihasilkan
Untuk singkatnya, panduan ini menunjukkan cara yang paling terstruktur untuk menggunakan IHttpClientFactory
, yaitu dengan menggunakan Typed Clients (pola Agen Layanan). Tetapi, semua opsi didokumentasikan dan saat ini tercantum dalam artikel ini yang mencakup IHttpClientFactory
penggunaan.
Catatan
Jika aplikasi Anda memerlukan cookie, mungkin lebih baik untuk menghindari penggunaan IHttpClientFactory di aplikasi Anda. Untuk cara alternatif mengelola klien, lihat Panduan untuk menggunakan klien HTTP
Cara menggunakan Klien Berjenis dengan IHttpClientFactory
Jadi, apa itu "Klien Berjenis"? Ini adalah HttpClient
yang telah dikonfigurasi sebelumnya untuk beberapa penggunaan tertentu. Konfigurasi ini dapat mencakup nilai-nilai tertentu seperti server dasar, header HTTP atau waktu habis.
Diagram berikut menunjukkan bagaimana Klien Berjenis digunakan dengan IHttpClientFactory
:
Gambar 8-4. Menggunakan IHttpClientFactory
dengan kelas Klien Berjenis.
Pada gambar di atas, ClientService
(digunakan oleh pengontrol atau kode klien) menggunakan yang HttpClient
dibuat oleh IHttpClientFactory
yang terdaftar. Pabrik ini menetapkan HttpMessageHandler
dari kumpulan ke HttpClient
. HttpClient
dapat dikonfigurasi dengan kebijakan Polly saat mendaftarkan IHttpClientFactory
dalam kontainer DI dengan metode ekstensi AddHttpClient.
Untuk mengonfigurasi struktur di atas, tambahkan IHttpClientFactory di aplikasi Anda dengan memasang peket NuGet Microsoft.Extensions.Http
yang menyertakan metode ekstensi AddHttpClient untuk IServiceCollection. Metode ekstensi ini mendaftarkan kelas DefaultHttpClientFactory
internal yang akan digunakan sebagai singleton untuk antarmuka IHttpClientFactory
. Ini mendefinisikan konfigurasi sementara untuk HttpMessageHandlerBuilder. Penanganan pesan (objek HttpMessageHandler) ini, diambil dari kumpulan, digunakan oleh HttpClient
dikembalikan dari pabrik.
Dalam cuplikan berikutnya, Anda dapat melihat bagaimana AddHttpClient()
dapat digunakan untuk mendaftarkan Klien Jenis (Agen Layanan) yang perlu menggunakan 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>();
Mendaftarkan layanan klien seperti yang ditunjukkan pada cuplikan sebelumnya, membuat DefaultClientFactory
membuat standar HttpClient
untuk setiap layanan. Klien berjenis terdaftar sebagai sementara dengan kontainer DI. Dalam kode sebelumnya, AddHttpClient()
mendaftarkan CatalogService, BasketService, OrderingService sebagai layanan sementara sehingga mereka dapat disuntikkan dan digunakan langsung tanpa perlu registrasi tambahan.
Anda juga dapat menambahkan konfigurasi khusus instans dalam pendaftaran ke, misalnya, mengonfigurasi alamat dasar, dan menambahkan beberapa kebijakan ketahanan, seperti yang ditunjukkan dalam hal berikut:
builder.Services.AddHttpClient<ICatalogService, CatalogService>(client =>
{
client.BaseAddress = new Uri(builder.Configuration["BaseUrl"]);
})
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
Dalam contoh berikutnya ini, Anda dapat melihat konfigurasi salah satu kebijakan di atas:
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
Anda dapat menemukan detail selengkapnya tentang menggunakan Polly di artikel Berikutnya.
Masa pakai HttpClient
Setiap kali Anda mendapatkan objek HttpClient
dari IHttpClientFactory
, instans baru akan dikembalikan. Tetapi masing-masing HttpClient
menggunakan HttpMessageHandler
yang dikumpulkan dan digunakan kembali oleh IHttpClientFactory
untuk mengurangi konsumsi sumber daya, selama masa pakai HttpMessageHandler
belum kedaluwarsa.
Pengumpulan penanganan diinginkan karena setiap penanganan biasanya mengelola sambungan HTTP yang mendasarinya sendiri; membuat lebih banyak penanganan dibandingkan yang diperlukan dapat mengakibatkan penundaan sambungan. Beberapa penanganan juga menjaga koneksi tetap terbuka tanpa batas, yang dapat mencegah penanganan bereaksi terhadap perubahan DNS.
Objek HttpMessageHandler
di kumpulan memiliki masa pakai yang merupakan lamanya waktu instans HttpMessageHandler
di kumpulan dapat digunakan kembali. Nilai defaultnya adalah dua menit, tetapi dapat ditimpa per Klien Berjenis. Untuk mengambilalih, panggil SetHandlerLifetime()
IHttpClientBuilder yang dikembalikan saat membuat klien, seperti yang ditunjukkan dalam kode berikut:
//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));
Setiap Klien Berjenis dapat memiliki nilai masa pakai penanganan yang dikonfigurasi sendiri. Atur masa pakai ke InfiniteTimeSpan
untuk menonaktifkan kedaluwarsa penanganan.
Terapkan kelas Klien Berjenis Anda yang menggunakan HttpClient yang disuntikkan dan dikonfigurasi
Sebagai langkah sebelumnya, Anda harsu menentukan kelas Klien Berjenis, seperti kelas dalam kode sampel, seperti 'BasketService', 'CatalogService', 'OrderingService', dll. – Klien Berjenis adalah kelas yang menerima objek HttpClient
(disuntikkan melalui konstruktornya) dan menggunakannya untuk memanggil beberapa layanan HTTP jarak jauh. Misalnya:
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;
}
}
Klien Jenis (CatalogService
dalam contoh) diaktifkan oleh DI (Injeksi Dependensi), yang berarti dapat menerima layanan terdaftar apa pun di konstruktornya, selain HttpClient
.
Klien Berjenis secara efektif adalah objek sementara, yang berarti instans baru dibuat setiap kali diperlukan. Ini menerima instans HttpClient
baru setiap kali dibangun. Tetapi objek HttpMessageHandler
di kumpulan adalah objek yang digunakan kembali oleh beberapa instans HttpClient
.
Menggunakan kelas Klien Berjenis
Terakhir, setelah kelas yang diketik diimplementasikan, Anda dapat mendaftarkannya dan dikonfigurasi dengan AddHttpClient()
. Setelah itu Anda dapat menggunakannya di mana pun layanan disuntikkan oleh DI, seperti di kode halaman Razor atau pengontrol aplikasi web MVC, yang ditunjukkan dalam kode di bawah ini dari 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
}
}
}
Hingga titik ini, cuplikan kode di atas hanya menunjukkan contoh melakukan permintaan HTTP reguler. Tetapi 'sihir' hadir di bagian berikut di mana ia menunjukkan bagaimana semua permintaan HTTP yang dibuat oleh HttpClient
dapat memiliki kebijakan tangguh seperti mencoba kembali dengan backoff eksponensial, pemutus sirkuit, fitur keamanan menggunakan token autentikasi, atau bahkan fitur kustom lainnya. Dan semua ini dapat dilakukan hanya dengan menambahkan kebijakan dan mendelegasikan penanganan ke Klien Berjenis terdaftar Anda.
Sumber daya tambahan
Panduan HttpClient untuk .NET
https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelinesMenggunakan HttpClientFactory di .NET
https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factoryMenggunakan HttpClientFactory di ASP.NET Core
https://learn.microsoft.com/aspnet/core/fundamentals/http-requestsKode sumber HttpClientFactory di
dotnet/runtime
repositori GitHub
https://github.com/dotnet/runtime/tree/release/7.0/src/libraries/Microsoft.Extensions.Http/Polly (pustaka ketahanan.NET dan penanganan kesalahan sementara)
https://thepollyproject.azurewebsites.net/
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk