如何在WebClient中正确获取自定义错误正文消息?

时间:2020-09-02 08:06:49

标签: java spring-boot spring-webflux spring-webclient

我要实现的目标是使用404代码获取响应错误,并使用WebClient获取错误正文,我该如何正确执行此操作?

这是我的错误代码为404的响应,以及来自其他API的正文响应:

{
  "timestamp": "2020-09-02T07:36:01.960+00:00",
  "message": "Data not found!",
  "details": "uri=/api/partnershipment/view"
}

这是我的消耗代码:

    Map<String,Long> req = new HashMap<String,Long>();
    req.put("id", 2L);

    PartnerShipmentDto test = webClient.post()
    .uri(urlTest).body(Mono.just(req), PartnerShipmentDto.class)
    .exchange()
    .flatMap(res -> {
        if(res.statusCode().isError()){
            res.body((clientHttpResponse, context) -> {
                throw new ResourceNotFound(clientHttpResponse.getBody().toString());
            });
            throw new ResourceNotFound("aaaa");

        } else {
            return res.bodyToMono(PartnerShipmentDto.class);
        }
    })
    .block();

这是我的ResourNotFound.java类:

@SuppressWarnings("serial")
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFound extends RuntimeException {
    
    public ResourceNotFound(String message){
        super(message);
    }
    
}

这是使用@ControllerAdvice的全局异常处理程序:

@ControllerAdvice
@RestController
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public final ResponseEntity<Object> handleAllException(Exception ex, WebRequest request) {

        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
        logger.error(ex.getMessage());
        return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(ResourceNotFound.class)
    public final ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFound ex, WebRequest request) {

        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
        logger.error(ex.getMessage());
        return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
    }

}

但是我在ResourceNotFound异常中打印的响应是这样的(这是我从消费者方面的错误):

{
  "timestamp": "2020-09-02T07:50:48.132+00:00",
  "message": "FluxMap",
  "details": "uri=/api/shipmentaddressgrouping/store"
}

它只写了“ FluxMap”,我如何获得“消息”字段?我也想获取“时间戳”和“详细信息”字段

1 个答案:

答案 0 :(得分:1)

您提供的示例代码的主要问题是以下代码行

throw new ResourceNotFound(clientHttpResponse.getBody().toString());

此类型为Flux<DataBuffer>,而不是实际的响应主体。这会导致您遇到的问题。

解决此问题的方法是在错误响应正文上调用bodyToMono方法并映射到Java对象。这可以通过从Web客户端公开的onStatus操作符来完成,该操作符使您可以对特定的状态码执行特定的操作。

下面的代码段应解决此问题

    webClient.post()
            .uri(uriTest).body(Mono.just(req), PartnerShipmentDto.class)
            .retrieve()
            .onStatus(HttpStatus::isError, res -> res.bodyToMono(ErrorBody.class)
                    .onErrorResume(e -> Mono.error(new ResourceNotFound("aaaa")))
                    .flatMap(errorBody -> Mono.error(new ResourceNotFound(errorBody.getMessage())))
            )
            .bodyToMono(PartnerShipmentDto.class)
            .block();

ErrorBody应该包含要从json映射到java对象的所有字段。下面的示例仅映射“消息”字段。

public class ErrorBody {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}