Table Of Content
- 1. Giới thiệu
- 2. IHttpClientFactory là gì?
- 3. Cách sử dụng IHttpClientFactory
- 3.1. Đăng ký IHttpClientFactory
- 3.2. Sử dụng IHttpClientFactory
- a. Sử dụng trực tiếp IHttpClientFactory
- b. Sử dụng Named Client
- c. Sử dụng Typed Client
- 4. Kết hợp IHttpClientFactory với Polly để xử lý lỗi
- 4.1. Retry Policy
- 4.2. Circuit Breaker Policy
- 4.3. Kết hợp Retry và Circuit Breaker
- 5. Tổng kết
1. Giới thiệu
Trong quá trình phát triển các ứng dụng web hiện đại, việc giao tiếp với các API bên ngoài là một nhiệm vụ quan trọng. Tuy nhiên, nếu không được quản lý hợp lý, HttpClient
có thể dẫn đến các vấn đề nghiêm trọng về hiệu năng, tài nguyên và bảo mật. Bài viết này sẽ giới thiệu IHttpClientFactory
– một tính năng mạnh mẽ của ASP.NET Core giúp giải quyết những thách thức này, tối ưu hóa việc sử dụng HttpClient
, và mang lại một kiến trúc linh hoạt, dễ bảo trì hơn.
Trong các ứng dụng ASP.NET Core, việc gọi API từ các dịch vụ bên ngoài là một tác vụ phổ biến. Trước đây, HttpClient
thường được sử dụng trực tiếp, nhưng nếu không quản lý tốt, nó có thể dẫn đến các vấn đề về hiệu năng và tài nguyên như:
- Quản lý kết nối kém: Việc khởi tạo
HttpClient
nhiều lần có thể làm cạn kiệt số lượng kết nối khả dụng. - Bị giới hạn bởi DNS caching:
HttpClient
không tự động cập nhật khi DNS thay đổi. - Khó quản lý việc cấu hình và logging: Không có cách nào dễ dàng để quản lý việc ghi log hay theo dõi yêu cầu từ
HttpClient
. - Vấn đề về bảo mật: Việc khởi tạo nhiều
HttpClient
không kiểm soát có thể gây ra các lỗ hổng bảo mật. - Khả năng mở rộng bị hạn chế: Khi số lượng yêu cầu HTTP tăng lên, việc quản lý
HttpClient
không hiệu quả có thể dẫn đến bottleneck trong hệ thống.
ASP.NET Core giới thiệu IHttpClientFactory
để giải quyết các vấn đề này và cung cấp cách tiếp cận tối ưu hơn khi sử dụng HttpClient
.
2. IHttpClientFactory
là gì?
IHttpClientFactory
là một service được đăng ký trong Dependency Injection (DI) để tạo và quản lý HttpClient
một cách hiệu quả. Nó giúp:
- Tái sử dụng kết nối: Giảm thiểu việc tạo mới
HttpClient
, giúp tối ưu hiệu năng. - Tăng khả năng mở rộng: Cho phép cấu hình
HttpClient
theo từng yêu cầu cụ thể. - Hỗ trợ middleware (Delegating Handlers): Cho phép thêm các logic xử lý như caching, logging, retry policy một cách dễ dàng.
- Hỗ trợ quản lý lifecycle: Tránh các vấn đề liên quan đến
Socket Exhaustion
do sử dụngHttpClient
không đúng cách. - Hỗ trợ tracking và monitoring: Cho phép giám sát các request HTTP thông qua logging và diagnostic tools.
- Dễ dàng cấu hình retry, timeout: Kết hợp với thư viện như Polly để thiết lập retry policy hiệu quả.
3. Cách sử dụng IHttpClientFactory
Trước khi đi vào chi tiết, việc chọn cách sử dụng IHttpClientFactory
phụ thuộc vào yêu cầu của ứng dụng. Nếu bạn chỉ cần một cách nhanh chóng để tạo HttpClient
, có thể sử dụng trực tiếp IHttpClientFactory
. Nếu bạn muốn định nghĩa các cấu hình riêng biệt cho từng API, Named Client là lựa chọn phù hợp. Cuối cùng, nếu bạn muốn tách biệt logic gọi API vào một class riêng biệt để dễ bảo trì, Typed Client là lựa chọn tối ưu. Dưới đây là các cách sử dụng cụ thể:
3.1. Đăng ký IHttpClientFactory
Trong ASP.NET Core, IHttpClientFactory
được đăng ký vào DI bằng cách thêm vào Startup.cs
hoặc Program.cs
:
1 2 3 4 5 6 7 8 9 10 |
using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); // Đăng ký IHttpClientFactory builder.Services.AddHttpClient(); var app = builder.Build(); app.Run(); |
3.2. Sử dụng IHttpClientFactory
Có ba cách chính để sử dụng IHttpClientFactory
:
a. Sử dụng trực tiếp IHttpClientFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/test")] public class TestController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; public TestController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } [HttpGet] public async Task<IActionResult> GetData() { var client = _httpClientFactory.CreateClient(); var response = await client.GetStringAsync("https://api.github.com"); return Ok(response); } } |
b. Sử dụng Named Client
Named Clients giúp bạn định nghĩa các cấu hình cụ thể cho từng client.
1 2 3 4 5 6 7 8 |
builder.Services.AddHttpClient("github", client => { client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Demo"); client.DefaultRequestHeaders.Add("Authorization", "Bearer your-access-token"); client.Timeout = TimeSpan.FromSeconds(10); }); |
Ví dụ về tình huống sử dụng Named Client:
- Khi bạn cần gọi nhiều API khác nhau với các cấu hình riêng biệt.
- Khi API yêu cầu các header đặc biệt như
Authorization
hoặcAccept
. - Khi bạn muốn thiết lập timeout hoặc policies riêng cho từng API.
Sử dụng trong controller:
1 2 3 4 5 6 7 |
public async Task<IActionResult> GetGithubData([FromServices] IHttpClientFactory httpClientFactory) { var client = httpClientFactory.CreateClient("github"); var response = await client.GetStringAsync("repos/dotnet/aspnetcore"); return Ok(response); } |
Named Clients giúp bạn định nghĩa các cấu hình cụ thể cho từng client.
1 2 3 4 5 6 7 |
builder.Services.AddHttpClient("github", client => { client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Demo"); client.Timeout = TimeSpan.FromSeconds(10); }); |
Sử dụng trong controller:
1 2 3 4 5 6 7 |
public async Task<IActionResult> GetGithubData([FromServices] IHttpClientFactory httpClientFactory) { var client = httpClientFactory.CreateClient("github"); var response = await client.GetStringAsync("repos/dotnet/aspnetcore"); return Ok(response); } |
c. Sử dụng Typed Client
Typed Clients giúp bạn tổ chức mã nguồn tốt hơn bằng cách bọc HttpClient
vào một class riêng.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class GitHubService { private readonly HttpClient _httpClient; public GitHubService(HttpClient httpClient) { _httpClient = httpClient; _httpClient.BaseAddress = new Uri("https://api.github.com/"); _httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Demo"); } public async Task<string> GetRepoData() { return await _httpClient.GetStringAsync("repos/dotnet/aspnetcore"); } } |
4. Kết hợp IHttpClientFactory
với Polly để xử lý lỗi
IHttpClientFactory
hỗ trợ tích hợp với Polly, giúp thực hiện retry, circuit breaker khi gọi API bị lỗi.
4.1. Retry Policy
1 2 3 4 5 6 7 8 9 10 11 |
using Polly; using Polly.Extensions.Http; using Polly.Retry; var retryPolicy = HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); builder.Services.AddHttpClient("github") .AddPolicyHandler(retryPolicy); |
4.2. Circuit Breaker Policy
Bên cạnh cơ chế retry, Circuit Breaker giúp ngăn chặn hệ thống tiếp tục gửi yêu cầu khi phát hiện lỗi liên tục trong một khoảng thời gian nhất định. Điều này giúp bảo vệ hệ thống khỏi bị quá tải và cải thiện độ ổn định của ứng dụng.
1 2 3 4 5 6 7 8 9 10 |
var circuitBreakerPolicy = HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync( handledEventsAllowedBeforeBreaking: 5, durationOfBreak: TimeSpan.FromSeconds(30) ); builder.Services.AddHttpClient("github") .AddPolicyHandler(circuitBreakerPolicy); |
Với cấu hình trên, nếu có 5 lỗi liên tiếp, Circuit Breaker sẽ tạm thời ngăn chặn các request trong 30 giây trước khi thử lại. Điều này giúp giảm tải áp lực lên hệ thống khi một dịch vụ bên ngoài gặp sự cố.
4.3. Kết hợp Retry và Circuit Breaker
Thông thường, ta nên kết hợp cả hai chính sách để có khả năng khắc phục sự cố linh hoạt hơn:
1 2 3 4 |
builder.Services.AddHttpClient("github") .AddPolicyHandler(retryPolicy) .AddPolicyHandler(circuitBreakerPolicy); |
Việc áp dụng cả hai giúp đảm bảo ứng dụng có thể thử lại khi gặp lỗi tạm thời, đồng thời ngăn ngừa việc gửi quá nhiều yêu cầu khi dịch vụ bên ngoài không hoạt động ổn định.
IHttpClientFactory
hỗ trợ tích hợp với Polly, giúp thực hiện retry, circuit breaker khi gọi API bị lỗi.
1 2 3 4 5 6 7 8 9 10 11 |
using Polly; using Polly.Extensions.Http; using Polly.Retry; var retryPolicy = HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); builder.Services.AddHttpClient("github") .AddPolicyHandler(retryPolicy); |
5. Tổng kết
IHttpClientFactory
là một cải tiến lớn trong ASP.NET Core giúp tối ưu hóa việc sử dụng HttpClient
. Nó giải quyết các vấn đề về quản lý kết nối, cấu hình, logging và xử lý lỗi một cách hiệu quả. Khi sử dụng IHttpClientFactory
, bạn có thể:
- Quản lý
HttpClient
tốt hơn, tránh lỗi kết nối. - Cấu hình linh hoạt với Named và Typed Clients.
- Kết hợp với Polly để tăng độ ổn định.
- Cải thiện bảo mật và khả năng mở rộng của hệ thống.
- Theo dõi và ghi log các request một cách hiệu quả.
- Bảo vệ ứng dụng khỏi các lỗ hổng bảo mật tiềm ẩn, giúp tránh rò rỉ tài nguyên và các cuộc tấn công liên quan đến quản lý kết nối không đúng cách.
- Quản lý lifecycle của
HttpClient
hiệu quả, giúp ngăn ngừa vấn đềSocket Exhaustion
và cải thiện hiệu năng hệ thống.
Nếu ứng dụng của bạn thường xuyên gọi API bên ngoài, đây là một công cụ rất hữu ích giúp bạn tối ưu hiệu năng và bảo trì mã nguồn dễ dàng hơn.
IHttpClientFactory
là một cải tiến lớn trong ASP.NET Core giúp tối ưu hóa việc sử dụng HttpClient
. Nó giải quyết các vấn đề về quản lý kết nối, cấu hình, logging và xử lý lỗi một cách hiệu quả. Khi sử dụng IHttpClientFactory
, bạn có thể:
- Quản lý
HttpClient
tốt hơn, tránh lỗi kết nối. - Cấu hình linh hoạt với Named và Typed Clients.
- Kết hợp với Polly để tăng độ ổn định.
- Cải thiện bảo mật và khả năng mở rộng của hệ thống.
- Theo dõi và ghi log các request một cách hiệu quả.
Nếu ứng dụng của bạn thường xuyên gọi API bên ngoài, đây là một công cụ rất hữu ích giúp bạn tối ưu hiệu năng và bảo trì mã nguồn dễ dàng hơn.
No Comment! Be the first one.