【问题标题】:Get API response error message using Web Client Mono in Spring Boot在 Spring Boot 中使用 Web Client Mono 获取 API 响应错误消息
【发布时间】:2018-09-04 05:56:15
【问题描述】:

我正在使用 webflux Mono(在 Spring Boot 5 中)来使用外部 API。当 API 响应状态码为 200 时,我能够很好地获取数据,但是当 API 返回错误时,我无法从 API 中检索错误消息。 Spring webclient 错误处理程序始终将消息显示为

ClientResponse has erroneous status code: 500 Internal Server Error,但是当我使用 PostMan 时,API 返回此 JSON 响应,状态码为 500。

{
 "error": {
    "statusCode": 500,
    "name": "Error",
    "message":"Failed to add object with ID:900 as the object exists",
    "stack":"some long message"
   }
}

我使用WebClient的请求如下

webClient.getWebClient()
            .post()
            .uri("/api/Card")
            .body(BodyInserters.fromObject(cardObject))
            .retrieve()
            .bodyToMono(String.class)
            .doOnSuccess( args -> {
                System.out.println(args.toString());
            })
            .doOnError( e ->{
                e.printStackTrace();
                System.out.println("Some Error Happend :"+e);
            });

我的问题是,当 API 返回状态码为 500 的错误时,我如何才能访问 JSON 响应?

【问题讨论】:

    标签: spring spring-boot spring-webflux web-client


    【解决方案1】:

    如果要检索错误详细信息:

    WebClient webClient = WebClient.builder()
        .filter(ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            if (clientResponse.statusCode().isError()) {
                return clientResponse.bodyToMono(ErrorDetails.class)
                        .flatMap(errorDetails -> Mono.error(new CustomClientException(clientResponse.statusCode(), errorDetails)));
            }
            return Mono.just(clientResponse);
        }))
        .build();
    

    class CustomClientException extends WebClientException {
        private final HttpStatus status;
        private final ErrorDetails details;
    
        CustomClientException(HttpStatus status, ErrorDetails details) {
            super(status.getReasonPhrase());
            this.status = status;
            this.details = details;
        }
    
        public HttpStatus getStatus() {
            return status;
        }
    
        public ErrorDetails getDetails() {
            return details;
        }
    }
    

    并使用 ErrorDetails 类映射错误正文

    每个请求的变体:

    webClient.get()
        .exchange()
        .map(clientResponse -> {
            if (clientResponse.statusCode().isError()) {
                return clientResponse.bodyToMono(ErrorDetails.class)
                        .flatMap(errorDetails -> Mono.error(new CustomClientException(clientResponse.statusCode(), errorDetails)));
            }
            return clientResponse;
        })
    

    【讨论】:

    • 如何捕捉抛出的异常?
    • 什么是 ErrorDetails 类?
    • @2dsharp 你可以用 AbstractErrorWebExceptionHandler 捕获你的异常
    【解决方案2】:

    正如@Frischling 建议的那样,我将请求更改为如下所示

    return webClient.getWebClient()
     .post()
     .uri("/api/Card")
     .body(BodyInserters.fromObject(cardObject))
     .exchange()
     .flatMap(clientResponse -> {
         if (clientResponse.statusCode().is5xxServerError()) {
            clientResponse.body((clientHttpResponse, context) -> {
               return clientHttpResponse.getBody();
            });
         return clientResponse.bodyToMono(String.class);
       }
       else
         return clientResponse.bodyToMono(String.class);
    });
    

    我还注意到有几个从 1xx 到 5xx 的状态代码,这将使我在不同情况下更容易处理错误

    【讨论】:

    • 如果我的 Response 类不是 String 怎么办?这还能用吗?
    • @Rocky4Ever 是的,您只需更改预期的类型,它应该可以工作。顺便说一下,我不确定它是否适用于原始数据类型
    • exchange() 已弃用,但用exchangeToMono() 替换它和flatMap() 似乎可行。
    【解决方案3】:

    查看.onErrorMap(),它为您提供了查看的例外情况。由于您可能还需要exchange() 的body() 来查看,所以不要使用retrieve,而是

    .exchange().flatMap((ClientResponse) response -> ....);
    

    【讨论】:

      猜你喜欢
      • 2019-05-31
      • 1970-01-01
      • 1970-01-01
      • 2020-06-21
      • 2022-01-09
      • 2019-10-07
      • 2021-02-11
      • 1970-01-01
      • 2018-12-20
      相关资源
      最近更新 更多