Skip to content

12.4.1 GET tài nguyên

Ví dụ về việc sử dụng WebClient, giả sử bạn cần lấy một đối tượng Ingredient theo ID từ Taco Cloud API. Khi dùng RestTemplate, bạn có thể sử dụng phương thức getForObject(). Nhưng với WebClient, bạn xây dựng yêu cầu, nhận phản hồi, và sau đó trích xuất một Mono xuất bản đối tượng Ingredient, như minh họa sau:

java
Mono<Ingredient> ingredient = WebClient.create()
  .get()
  .uri("http://localhost:8080/ingredients/{id}", ingredientId)
  .retrieve()
  .bodyToMono(Ingredient.class);
  
ingredient.subscribe(i -> { ... });

Tại đây, bạn tạo một thể hiện mới của WebClient bằng create(). Sau đó, bạn sử dụng get()uri() để định nghĩa một yêu cầu GET đến http://localhost:8080/ingredients/{id}, trong đó {id} sẽ được thay thế bằng giá trị trong ingredientId. Phương thức retrieve() thực thi yêu cầu. Cuối cùng, lời gọi tới bodyToMono() trích xuất phần thân phản hồi vào một Mono<Ingredient> mà bạn có thể tiếp tục áp dụng các thao tác khác trên Mono.

Để áp dụng các thao tác bổ sung trên Mono được trả về từ bodyToMono(), điều quan trọng là bạn phải đăng ký (subscribe) nó, nếu không yêu cầu sẽ không bao giờ được gửi đi. Thực hiện các yêu cầu có thể trả về một tập hợp giá trị cũng rất dễ dàng. Ví dụ, đoạn mã sau đây lấy tất cả nguyên liệu:

java
Flux<Ingredient> ingredients = WebClient.create()
  .get()
  .uri("http://localhost:8080/ingredients")
  .retrieve()
  .bodyToFlux(Ingredient.class);
ingredients.subscribe(i -> { ... });

Phần lớn, việc lấy nhiều mục giống như gửi yêu cầu cho một mục đơn lẻ. Khác biệt lớn là thay vì sử dụng bodyToMono() để trích xuất phản hồi thành Mono, bạn sử dụng bodyToFlux() để trích xuất thành Flux.

Tương tự như bodyToMono(), Flux được trả về từ bodyToFlux() vẫn chưa được đăng ký. Điều này cho phép bạn áp dụng các thao tác bổ sung (lọc, ánh xạ, v.v.) lên Flux trước khi dữ liệu bắt đầu được truyền qua nó. Do đó, việc đăng ký Flux là rất quan trọng, nếu không yêu cầu sẽ không được gửi đi.

THỰC HIỆN YÊU CẦU VỚI MỘT BASE URI

Bạn có thể thấy rằng mình sử dụng cùng một base URI cho nhiều yêu cầu khác nhau. Trong trường hợp đó, việc tạo một bean WebClient với base URI và inject nó ở bất cứ đâu cần thiết sẽ rất hữu ích. Bean như vậy có thể được khai báo như sau (trong bất kỳ lớp nào được đánh dấu @Configuration):

java
@Bean
public WebClient webClient() {
  return WebClient.create("http://localhost:8080");
}

Then, anywhere you need to make requests using that base URI, the WebClient bean can be injected and used like this:

java
@Autowired
WebClient webClient;
public Mono<Ingredient> getIngredientById(String ingredientId) {
  Mono<Ingredient> ingredient = webClient
    .get()
    .uri("/ingredients/{id}", ingredientId)
    .retrieve()
    .bodyToMono(Ingredient.class);

  ingredient.subscribe(i -> { ... });
}

Vì WebClient đã được tạo sẵn, bạn có thể bắt đầu làm việc ngay bằng cách gọi get(). Còn về URI, bạn chỉ cần chỉ định đường dẫn tương đối so với base URI khi gọi uri().

GIỚI HẠN THỜI GIAN CHỜ VỚI CÁC YÊU CẦU KÉO DÀI

Một điều bạn có thể chắc chắn là mạng không phải lúc nào cũng đáng tin cậy hoặc nhanh như bạn mong đợi. Hoặc có thể một máy chủ từ xa xử lý yêu cầu một cách chậm chạp. Lý tưởng nhất là một yêu cầu tới dịch vụ từ xa sẽ trả về trong thời gian hợp lý. Nhưng nếu không, sẽ rất tuyệt nếu client không bị kẹt khi chờ phản hồi quá lâu.

Để tránh việc client của bạn bị trì hoãn bởi một mạng chậm hoặc dịch vụ không phản hồi kịp, bạn có thể sử dụng phương thức timeout() từ Flux hoặc Mono để đặt giới hạn thời gian chờ cho dữ liệu được xuất bản. Ví dụ, hãy xem bạn có thể sử dụng timeout() như thế nào khi lấy dữ liệu nguyên liệu trong đoạn mã sau:

java
Flux<Ingredient> ingredients = webclient
  .get()
  .uri("/ingredients")
  .retrieve()
  .bodyToFlux(Ingredient.class);

ingredients
  .timeout(Duration.ofSeconds(1))
  .subscribe(
    i -> { ... },
    e -> {
    //handle timeout error
  });

Như bạn thấy, trước khi đăng ký Flux, bạn đã gọi timeout() và chỉ định thời lượng là 1 giây. Nếu yêu cầu có thể hoàn tất trong thời gian dưới 1 giây, thì không có vấn đề gì. Nhưng nếu yêu cầu mất hơn 1 giây, nó sẽ bị timeout, và trình xử lý lỗi được truyền làm tham số thứ hai cho subscribe() sẽ được gọi.

Released under the MIT License.