1. 概述
RESTful 服务可能会因各种原因失败。在这个教程中,我们将探讨如何在集成的 REST 服务抛出错误时,从 Feign 客户端获取原始消息。
2. Feign 客户端
Feign 是一个可插拔且声明式的 Web 服务客户端,它使编写 Web 服务客户端变得更加容易。除了 Feign 注解,它还支持 JAX-RS,并且提供了编码器和解码器,以提供更多的自定义选项。
3. 从 ErrorDecoder
中获取消息
当出现错误时,Feign 客户端会隐藏原始消息,为了获取它,我们需要编写一个自定义的 ErrorDecoder
。如果没有这样的自定义,我们将会看到以下错误:
feign.FeignException$NotFound: [404] during [POST] to [http://localhost:8080/upload-error-1] [UploadClient#fileUploadError(MultipartFile)]: [{"timestamp":"2022-02-18T13:25:22.083+00:00","status":404,"error":"Not Found","path":"/upload-error-1"}]
at feign.FeignException.clientErrorStatus(FeignException.java:219) ~[feign-core-11.7.jar:na]
at feign.FeignException.errorStatus(FeignException.java:194) ~[feign-core-11.7.jar:na]
为了处理这个错误,我们将创建一个简单的 ExceptionMessage
Java 对象来表示错误消息:
public class ExceptionMessage {
private String timestamp;
private int status;
private String error;
private String message;
private String path;
// standard getters and setters
}
现在,让我们通过在自定义的 ErrorDecoder
实现中提取它来获取原始消息:
public class RetreiveMessageErrorDecoder implements ErrorDecoder {
private ErrorDecoder errorDecoder = new Default();
@Override
public Exception decode(String methodKey, Response response) {
ExceptionMessage message = null;
try (InputStream bodyIs = response.body()
.asInputStream()) {
ObjectMapper mapper = new ObjectMapper();
message = mapper.readValue(bodyIs, ExceptionMessage.class);
} catch (IOException e) {
return new Exception(e.getMessage());
}
switch (response.status()) {
case 400:
return new BadRequestException(message.getMessage() != null ? message.getMessage() : "Bad Request");
case 404:
return new NotFoundException(message.getMessage() != null ? message.getMessage() : "Not found");
default:
return errorDecoder.decode(methodKey, response);
}
}
}
在我们的实现中,我们基于可能的错误添加了逻辑,因此可以根据需要进行定制。在 switch 块的默认情况下,我们使用了 Default
的 ErrorDecoder
实现。
Default
实现会在状态不在 2xx 范围内时解码 HTTP 响应。如果 throwable
是可重试的(retryable
),那么它应该是 RetryableException
的子类,并且我们应该尽可能地抛出应用特定的异常。
为了配置我们自定义的 ErrorDecoder
,我们将在 Feign 配置中添加我们的实现作为 bean:
@Bean
public ErrorDecoder errorDecoder() {
return new RetreiveMessageErrorDecoder();
}
现在,让我们看看带有原始消息的异常:
com.baeldung.cloud.openfeign.exception.NotFoundException: Page Not found
at com.baeldung.cloud.openfeign.fileupload.config.RetreiveMessageErrorDecoder.decode(RetreiveMessageErrorDecoder.java:30) ~[classes/:na]
at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96) ~[feign-core-11.7.jar:na]
4. 总结
在这篇文章中,我们展示了如何定制 ErrorDecoder
,以便我们可以捕获 Feign 错误并获取原始消息。
如往常一样,本教程中使用的所有代码示例都可以在 GitHub 上找到。