Skip to content

12.4.4 Xử lý lỗi

Tất cả các ví dụ về WebClient cho đến nay đều giả định rằng mọi thứ diễn ra suôn sẻ; không có phản hồi nào với mã trạng thái thuộc cấp độ 400 hoặc 500. Nếu một trong hai loại mã lỗi này được trả về, WebClient sẽ ghi lại lỗi và tiếp tục mà không có sự cố nào.

Nếu bạn cần xử lý các lỗi như vậy, bạn có thể sử dụng phương thức onStatus() để chỉ định cách xử lý các mã trạng thái HTTP khác nhau. onStatus() chấp nhận hai hàm: một hàm điều kiện (predicate function), dùng để kiểm tra khớp với mã trạng thái HTTP, và một hàm nhận đối tượng ClientResponse và trả về một Mono<Throwable>.

Để minh hoạ cách sử dụng onStatus() để tạo một bộ xử lý lỗi tuỳ chỉnh, hãy xem xét ví dụ sau sử dụng WebClient để truy xuất một nguyên liệu dựa trên ID của nó:

java
Mono<Ingredient> ingredientMono = webClient
  .get()
  .uri("http://localhost:8080/ingredients/{id}", ingredientId)
  .retrieve()
  .bodyToMono(Ingredient.class);

Miễn là giá trị trong ingredientId khớp với một tài nguyên nguyên liệu đã biết, thì Mono trả về sẽ phát hành đối tượng Ingredient khi được subscribe. Nhưng chuyện gì sẽ xảy ra nếu không có nguyên liệu nào khớp?

Khi đăng ký (subscribe) vào một Mono hoặc Flux có thể kết thúc bằng lỗi, điều quan trọng là bạn cần đăng ký một consumer cho lỗi bên cạnh consumer cho dữ liệu trong lời gọi subscribe() như sau:

java
ingredientMono.subscribe(
    ingredient -> {
    // handle the ingredient data
    ...
    },
    error-> {
    // deal with the error
    ...
    });

Nếu tài nguyên nguyên liệu được tìm thấy, thì lambda đầu tiên (consumer dữ liệu) được cung cấp cho subscribe() sẽ được gọi với đối tượng Ingredient tương ứng. Nhưng nếu không tìm thấy, yêu cầu sẽ phản hồi với mã trạng thái HTTP 404 (KHÔNG TÌM THẤY), và kết quả là lambda thứ hai (consumer lỗi) sẽ được gọi và mặc định nhận một đối tượng WebClientResponseException.

Vấn đề lớn nhất với WebClientResponseException là nó khá chung chung về nguyên nhân khiến Mono thất bại. Tên của nó gợi ý rằng có lỗi trong phản hồi từ một yêu cầu được tạo ra bởi WebClient, nhưng bạn cần kiểm tra kỹ WebClientResponseException để biết chính xác điều gì đã xảy ra. Dù sao đi nữa, sẽ tốt hơn nếu exception được truyền đến consumer lỗi mang tính đặc thù của miền nghiệp vụ hơn là cụ thể của WebClient.

Bằng cách thêm một trình xử lý lỗi tuỳ chỉnh, bạn có thể cung cấp mã để chuyển đổi mã trạng thái thành một Throwable do bạn tự định nghĩa. Giả sử bạn muốn một yêu cầu thất bại khi truy xuất tài nguyên nguyên liệu sẽ khiến Mono kết thúc với lỗi UnknownIngredientException. Bạn có thể thêm lời gọi onStatus() sau lời gọi retrieve() để thực hiện điều đó:

java
Mono<Ingredient> ingredientMono = webClient
  .get()
  .uri("http://localhost:8080/ingredients/{id}", ingredientId)
  .retrieve()
  .onStatus(HttpStatus::is4xxClientError,
      response -> Mono.just(new UnknownIngredientException()))
  .bodyToMono(Ingredient.class);

Đối số đầu tiên trong lời gọi onStatus() là một predicate được truyền vào một HttpStatus và trả về true nếu mã trạng thái đó là mã bạn muốn xử lý. Nếu mã trạng thái khớp, phản hồi sẽ được truyền đến hàm trong đối số thứ hai để xử lý tuỳ ý, và cuối cùng trả về một Mono kiểu Throwable.

Trong ví dụ, nếu mã trạng thái nằm trong nhóm mã lỗi 400 (ví dụ: lỗi từ phía client), thì một Mono sẽ được trả về với một exception kiểu UnknownIngredientException. Điều này khiến ingredientMono thất bại với exception đó.

Lưu ý rằng HttpStatus::is4xxClientError là một method reference đến phương thức is4xxClientError của lớp HttpStatus. Đây là phương thức sẽ được gọi trên đối tượng HttpStatus được truyền vào. Nếu muốn, bạn có thể sử dụng một phương thức khác của HttpStatus dưới dạng method reference; hoặc bạn có thể cung cấp hàm của riêng bạn dưới dạng lambda hoặc method reference trả về giá trị boolean.

Ví dụ, bạn có thể xử lý lỗi cụ thể hơn bằng cách kiểm tra chính xác mã trạng thái HTTP 404 (KHÔNG TÌM THẤY) bằng cách thay đổi lời gọi onStatus() như sau:

java
Mono<Ingredient> ingredientMono = webClient
  .get()
  .uri("http://localhost:8080/ingredients/{id}", ingredientId)
  .retrieve()
  .onStatus(status -> status == HttpStatus.NOT_FOUND,
      response -> Mono.just(new UnknownIngredientException()))
  .bodyToMono(Ingredient.class);

Cũng cần lưu ý rằng bạn có thể có nhiều lời gọi onStatus() nếu cần để xử lý đa dạng các mã trạng thái HTTP khác nhau có thể được trả về trong phản hồi.

Released under the MIT License.