如何在 Webflux WebClient 中自定义异常?

How do custom exception in Webflux WebClient?

在我的 webflux 应用程序中,我想通过 WebClient 发送一些请求。我想处理所有条件(200401403.. . 响应),然后向客户端响应 json。对于错误状态代码,我想使用@RestControllerAdvice,所以我必须抛出一个自定义异常,然后在控制器建议中处理自定义 json。查看示例代码:

WebClient.create().post
   .uri("URI")
   .retrieve()
   .onStatus(HttpStatus::is4xxClientError, {
       // create Mono<CustomException> 
   }
   .bodyToMono(ResponseDto.class)

现在异常处理如下:

@ResponseBody
@ResponseStatus(...)
@ExceptionHandler(CustomException1.class)
public void customException1(CustomException1 exception) {
   //do Something width response body
}

@ExceptionHandler(CustomException2.class)
public void customException2(CustomException2 exception) {
   //do Something width response body
}

Webclient 得到一个 401 响应 json 正文如下:

{
   "message": "Password is incorrect"
}

我可以创建Mono.error(new CustomException()),但问题是 WebClient 响应正文。如果消息是"Password is incorrect",我想发送客户端:

Username or Password is incorrect

我该怎么做?

我从未使用过 WebFlux,但我找到了 。看起来您可以通过在 onStatus 处理程序函数中编写 return Mono.error(new CustomException1()); 来抛出异常。根据描述,bodyToMono(Class)方法会抛出异常。

最后,您可以像这样修改您的 ControllerAdvice:

@ExceptionHandler(CustomException.class)
public ResponseEntity<CustomErrorModel> customException(CustomException exception) {
   return new ResponseEntity<>( new CustomErrorModel(), HttpStatus.BAD_REQUEST );
}

正如我所说 - 我没有测试它,但它可能对你有所提示。

请检查以下 API 实现,它处理调用的 rest api 调用的错误响应。我假设我们知道 api 的响应,所以我创建了 ResponseDTO class.

Controller.java

@GetMapping("/webclient/test")
public ResponseDTO testWebclient(@RequestBody RequestDTO requestPayload) {
    String url = "http://localhost:8080/api/write/simple";
    return WebClient.create()
            .post()
            .uri(url)
            .accept(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromObject(requestPayload))
            .retrieve()
            .onStatus(HttpStatus::is4xxClientError, response -> {
                return response.bodyToMono(ResponseDTO.class).flatMap(error -> {
                    return Mono.error(new CustomRuntimeException(error.getMessage(), response.statusCode(), error.getErrorCode()));
                });
            })
            .onStatus(HttpStatus::is5xxServerError, response -> {
                return response.bodyToMono(ResponseDTO.class).flatMap(error -> {
                    return Mono.error(new CustomRuntimeException(error.getMessage(), response.statusCode()));
                });
            })
            .bodyToMono(ResponseDTO.class);
}

ResponseDTO.java

public class ResponseDTO {

    private String message;
    private HttpStatus status;
    private ErrorCode errorCode;
    
    public ResponseDTO(String message, HttpStatus status) {
        this.message = message;
        this.status = status;
    }

    public ResponseDTO(String message, HttpStatus status, ErrorCode errorCode) {
        this.message = message;
        this.status = status;
        this.errorCode = errorCode;
    }
    /** getters **/
}

ErrorCode.java

    public class ErrorCode {
        private String numCode;
        private String txtCode;
        
        /** getters **/
    }

要捕获异常,请在 @RestControllerAdvice 的 class 中添加以下代码片段(希望您已经知道)。

@ExceptionHandler(value = CustomRuntimeException.class)
public final ResponseEntity<ApiResponse> handleCustomRuntimeException(CustomRuntimeException exception) {
    List<ApiSubError> subErrors = Arrays.asList(new ApiSubError(exception.getMessage()));
    ApiResponse response = new ApiErrorResponse(exception.getMessage(), exception.getErrorCode());
    LOG.error("result: {}", response.getResult());
    return new ResponseEntity<>(response, exception.getHttpStatus());
}