如何在 WebClient 中正确获取自定义错误正文消息?
How to get custom error body message in WebClient properly?
我想要实现的是使用 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 class :
@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”,我如何获得“消息”字段?我也想获得“时间戳”和“详细信息”字段
您提供的示例代码的主要问题是以下代码行
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();
class ErrorBody
应包含您要从 json 映射到 java 对象的所有字段。下面的示例仅映射“消息”字段。
public class ErrorBody {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
我想要实现的是使用 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 class :
@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”,我如何获得“消息”字段?我也想获得“时间戳”和“详细信息”字段
您提供的示例代码的主要问题是以下代码行
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();
class ErrorBody
应包含您要从 json 映射到 java 对象的所有字段。下面的示例仅映射“消息”字段。
public class ErrorBody {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}