HttpClient
là một trong những lớp phổ biến trong .NET được dùng để gửi HTTP requests và nhận HTTP response từ một resource được xác định bởi một URI. Đây là một phần thiết yếu khi xây dựng các ứng dụng web hoặc microservices cần giao tiếp với các web service khác hoặc API bên ngoài.
Trong bài viết này, chúng ta sẽ khám phá cách sử dụng HttpClient
trong một ứng dụng ASP.NET Core, đưa ra các best practice và các sai lầm thường gặp.
HttpClient
là gì
HttpClient
là một class nằm trong namespace System.Net.Http
, nó được dùng để tạo các HTTP request như GET, POST, PUT, DELETE, … . Trong một ứng dụng ASP.NET Core, bạn có thể dùng HttpClient
để giao tiếp với các services hoặc APIs bên ngoài, bất kể chúng có base là RESTful hay SOAP.
Trong các phiên bản trước đây của .NET, việc khởi tạo một instance của lớp HttpClient
mỗi lần gửi một HTTP request là điều thường thấy. Tuy nhiên, việc này có thể dẫn tới vấn đề về hiệu năng, đặc biệt là khi socket cạn kiệt. Vì vậy, điều quan trọng là phải xử lý HttpClient
đúng cách trong các ứng dụng hiện đại.
Cách sử dụng HttpClient
trong ASP.NET Core
Trong một ứng dụng ASP.NET Core, ta nên tránh việc khởi tạo trực tiếp HttpClient
nhiều lần. Thay vào đó, dùng DI để quản lý lifecycle của nó. Điều này đảm bảo việc tái sử dụng HttpClient
xuyên suốt nhiều requests vào không dẫn tới các vấn đề liên quan đến việc quá tải kết nối.
Đăng ký HttpClient
vào DI
ASP.NET Core cung cấp hỗ trợ sẵn có cho HttpClient
thông qua IHttpClientFactory
, được khuyến nghị để quản lý các instance của lớp HttpClient
.
Sau đây là cách đăng ký và sử dụng HttpClient
trong ứng dụng của bạn:
- Đăng ký
IHttpClientFactory
trong phần cấu hình các services
Thêm đoạn code sau để đăng kýIHttpClientFactor
. Điều này cho phép bạn inject một thể hiện củaIHttpClientFactory
khi cần trong ứng dụng của bạn.services.AddHttpClient();
- Inject và sử dụng
HttpClient
Trong các class services hoặc controllers, bạn có thể injectIHttpClientFactory
và tạo ra các thể hiện của lớpHttpClient
.
Trong ví dụ trên, methodpublic class MyService
{
private readonly IHttpClientFactory _httpClientFactory;
public MyService(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<string> GetDataFromApiAsync()
{
var client = _httpClientFactory.CreateClient(); // Get HttpClient instance
var response = await client.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode(); // Throws exception if not successful
return await response.Content.ReadAsStringAsync();
}
}CreateClient()
cung cấp mộtHttpClient
có thể được tái sử dụng, có cấu hình mặc định.
Best practice khi sử dụng HttpClient
Tái sử dụng các thể hiện HttpClient
Như đã đề cập trước đó, việc tái sử dụng các thể hiện HttpClient
là rất quan trọng để tránh tình trạng cạn kiệt socket. Bằng cách sử dụng IHttpClientFactory
, ASP.NET Core quản lý việc tái sử dụng các kết nối HTTP một cách hiệu quả.
Tránh việc call đồng bộ
Khi gửi request, nên ưu tiên sử dụng các api bất đồng bộ như GetAsync()
, PostAsync()
,… thay vì các phương thức đồng bộ (như Get()
hoặc Post()
). Việc gọi các hàm blocking có thể làm giảm hiệu suất nghiêm trọng, đặc biệt là khi có tải lớn.
var result = await client.GetStringAsync("https://api.example.com");
Đặt giá trị timeout và xử lý ngoại lệ
Hãy đảm bảo bạn đã đặt một thời gian timeout phù hợp cho các HTTP request. HttpClient
sẽ ném ra ngoại lệ nếu request timeout. bạn có thể cấu hình timeout như sau:
services.AddHttpClient("MyApiClient", client =>
{
client.Timeout = TimeSpan.FromSeconds(30); // Set timeout to 30 seconds
});
Thêm vào đó, luôn xử lý các ngoại lệ có thể xảy ra trong quá trình gửi HTTP request. Nhưng ngoại lệ thường gặp bao gồm HttpRequestException
(vd: lỗi network) và TaskCanceledException
(vd: timeout).
Cấu hình HttpClient
với custom headers hoặc Authentication
Bạn có thể cấu hình HttpClient
để set các headers mặc định, auth token… Điều này hữu ích cho các API yêu cầu các headers tùy chỉnh, chẳng hạn như token OAuth:
services.AddHttpClient("MyApiClient", client =>
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer your_token_here");
});
Sử dụng named / typed HttpClient
Nếu bạn đang gọi các API bên ngoài khác nhau, hãy cân nhắc sử dụng named (được định danh bằng tên) hoặc typed (định nghĩa trước kiểu) clients để khiến cho code clean hơn và dễ bảo trì.
- Named clients: Đặt một định danh cho một client cụ thể và dùng nó khi cần:
services.AddHttpClient("MyNamedClient", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
});
- Typed clients: tạo một lớp cụ thể bao bọc
HttpClient
để có thể sử dụng các logic phức tạp hơn
public class MyApiClient
{
private readonly HttpClient _client;
public MyApiClient(HttpClient client)
{
_client = client;
}
public async Task<string> GetSomeDataAsync()
{
var response = await _client.GetAsync("endpoint");
return await response.Content.ReadAsStringAsync();
}
}
Đăng ký lớp này trong DI:
services.AddHttpClient<MyApiClient>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
});
Các lỗi sai thường gặp
- Không tái sử dụng
HttpClient
: Việc tạo một thể hiệnHttpClient
mới mỗi lần có thể dẫn đến tình trạng cạn kiệt socket. Hãy luôn tái sử dụng các thể hiệnHttpClient
thông qua DI (Dependency Injection) hoặcIHttpClientFactory
. - Chặn trong mã bất đồng bộ: Không sử dụng Task.Wait() hoặc Result trong mã bất đồng bộ. Điều này có thể dẫn đến deadlock và các nút thắt hiệu suất, đặc biệt là trong việc xử lý yêu cầu/phản hồi đồng bộ của ASP.NET Core.
- Không thiết lập thời gian chờ (Timeout): Luôn luôn thiết lập thời gian chờ, đặc biệt khi tương tác với các dịch vụ bên ngoài. Nếu không có thời gian chờ, các yêu cầu có thể bị treo vô thời hạn.
Kết luận
HttpClient
là một công cụ mạnh mẽ để thực hiện các HTTP request trong ASP.NET Core, nhưng việc sử dụng đúng cách là rất quan trọng để đảm bảo hiệu suất và độ tin cậy. Bằng cách tận dụng dịch vụ IHttpClientFactory
, bạn đảm bảo rằng các kết nối HTTP của mình được tái sử dụng, giảm thiểu chi phí và ngăn ngừa các vấn đề như cạn kiệt socket. Việc tuân thủ các phương pháp tốt như thiết lập thời gian chờ, xử lý ngoại lệ và sử dụng các phương thức bất đồng bộ sẽ giúp đảm bảo ứng dụng của bạn luôn phản hồi nhanh và hiệu quả.
Bằng cách áp dụng các mô hình này, ứng dụng của bạn có thể tương tác mượt mà với các API bên ngoài trong khi duy trì hiệu suất và khả năng mở rộng cao.
Tham khảo
https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient
https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines