99 Ngày Spring — Ngày 66: Gọi API ngoài bằng RestClient và WebClient
Một API ngoài có thể chậm, lỗi hoặc trả dữ liệu bất ngờ. Spring Framework 6.1, dùng trong Spring Boot 3.2 trở lên, cung cấp RestClient đồng bộ với fluent API; WebClient dùng mô hình reactive không chặn. Chọn theo cách ứng dụng xử lý luồng, rồi đặt giới hạn và hợp đồng lỗi rõ ràng.

1. RestClient cho luồng đồng bộ
RestClient phù hợp khi service/controller đang xử lý đồng bộ. Dùng RestClient.Builder do Boot cung cấp để giữ customizer và hạ tầng được cấu hình. retrieve() ánh xạ phản hồi; mã 4xx/5xx mặc định dẫn đến ngoại lệ, không phải DTO hợp lệ. Đặt base URL thay vì nối chuỗi URL rời rạc.
@Bean
RestClient catalog(RestClient.Builder builder) {
return builder.baseUrl("https://catalog.example").build();
}
Product getProduct(RestClient client, String id) {
return client.get().uri("/products/{id}", id)
.retrieve().body(Product.class);
}2. WebClient và hợp đồng không chặn
WebClient trả Mono/Flux và phù hợp pipeline WebFlux. Nếu gọi block() ngay trong event-loop, ta đánh mất lợi ích không chặn và có thể gây nghẽn. Một service MVC đồng bộ vẫn có thể dùng WebClient, nhưng cần lý do rõ ràng; chỉ đổi client không tự biến toàn bộ request thành reactive.
Mono<Product> getProduct(WebClient client, String id) {
return client.get().uri("/products/{id}", id)
.retrieve().bodyToMono(Product.class);
}3. Timeout và phân loại lỗi
Phân biệt lỗi kết nối, timeout, HTTP 4xx và 5xx. Đặt timeout ở HTTP client bên dưới, và một ngân sách tổng cho nghiệp vụ; timeout của một stage không luôn dừng được I/O nền. Không trả cùng một thông báo cho 404 của đối tác và lỗi mạng. Log endpoint, loại lỗi và thời gian, nhưng tránh ghi token hoặc dữ liệu nhạy cảm.
client.get().uri("/products/{id}", id)
.retrieve()
.onStatus(s -> s.value() == 404,
(req, res) -> { throw new ProductMissing(id); })
.body(Product.class);4. Retry chỉ khi an toàn
Retry một lỗi tạm thời có thể giúp, nhưng nhân tải lên đối tác đang quá tải. Giới hạn số lần, thêm backoff và jitter, và giữ tổng deadline. Với POST tạo đơn, chỉ retry khi có idempotency key hoặc cam kết từ API đối tác. Test 429, 5xx, timeout và phản hồi chậm trước khi triển khai.
Chọn RestClient cho luồng MVC đồng bộ; giữ Mono xuyên suốt luồng WebFlux.
Theo dõi tỷ lệ lỗi, độ trễ và số lần retry theo từng đối tác.
Client HTTP là một ranh giới lỗi của hệ thống. Chọn kiểu gọi phù hợp, đặt timeout ở đúng lớp và retry có điều kiện. Ngày 67 kiểm tra dữ liệu vào bằng custom validation.
Tài liệu đối chiếu
https://docs.spring.io/spring-framework/reference/integration/rest-clients.html
https://docs.spring.io/spring-boot/3.5/reference/io/rest-client.html
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


