如何为多个假客户端实现错误解码器
How implement Error decoder for multiple feign clients
我在一个 Spring 引导应用程序中有多个伪装客户端。我正在使用 Controller Advice 来处理每个假装客户端的自定义异常。
这里我的控制器建议处理两个自定义异常(每个客户端一个:client1 和 client2):
@ControllerAdvice
public class ExceptionTranslator implements ProblemHandling {
@ExceptionHandler
public ResponseEntity<Problem> handleCustomClient1Exception(CustomException1 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
@ExceptionHandler
public ResponseEntity<Problem> handleCustomClient2Exception(CustomException2 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
}
我已经为 feign client1 实现了一个错误解码器。
public class ClientErrorDecoder implements ErrorDecoder {
final ObjectMapper mapper;
public ClientErrorDecoder() {
this.mapper = new ObjectMapper();
}
@Override
public Exception decode(String methodKey, Response response) {
ExceptionDTO exceptionDTO;
try {
exceptionDTO = mapper.readValue(response.body().asInputStream(), ExceptionDTO.class);
} catch (IOException e) {
throw new RuntimeException("Failed to process response body.", e);
}
return new CustomException1(exceptionDTO.getDetail(), exceptionDTO.getCode(), exceptionDTO.getTitle(), exceptionDTO.getStatus());
}
}
我还配置了 feign,以便为特定客户端使用该错误解码器,如下所示:
feign:
client:
config:
client1:
errorDecoder: feign.codec.ErrorDecoder.Default
我的问题是:处理多个客户端异常的最佳方法是什么?我应该使用相同的错误解码器并将它们的响应视为一般异常吗?或者我应该为每个假客户端创建一个错误解码器?
快速解答
如果您使用不同的 API,错误响应的格式将不同。因此,分别处理它们似乎是最好的方法。
备注
从你的例子来看,你似乎定义了一个自定义 ErrorDecoder
不被使用,因为您还在属性文件中配置了假装为您的 client1 使用默认错误解码器。
即使你在某处定义了一个 @Configuration
class 和你的自定义 ClientErrorDecoder
的 bean,
Spring Cloud documentation 提到配置属性优先于 @Configuration
注释
If we create both @Configuration bean and configuration properties,
configuration properties will win. It will override @Configuration
values. But if you want to change the priority to @Configuration, you
can change feign.client.default-to-properties to false.
例子
这是一个假设的修剪配置,用于处理具有不同错误解码器的多个假客户端:
客户端 1:
您告诉 feign 为 client1
加载 CustomFeignConfiguration
class 中定义的 bean
@FeignClient(name = "client1", configuration = {CustomFeignConfiguration.class})
public interface Client1 {...}
客户端 2:
Client2 将使用默认的 Feign ErrorDecoder
因为没有指定配置。 (将在错误时抛出 FeignException
)
@FeignClient(name = "client2")
public interface Client2 {...}
Configuration:这里要注意,如果在CustomFeignConfiguration
中加上@Configuration
,那么会使用ClientErrorDecoder
bean 对于每个加载的假客户端(取决于您的应用程序组件扫描行为)
public class CustomFeignConfiguration {
@Bean
public ClientErrorDecoder clientErrorDecoder(ObjectMapper objectMapper) {
return new ClientErrorDecoder(objectMapper);
}
}
此配置也可以使用属性文件完成。
旁注
在我看来,您甚至不需要控制器建议。如果您使用 Spring Web @ResponseStatus
注释,您可以判断应该将哪个 HTTP 状态代码与您的自定义 ErrorDecoder
.
抛出的异常主体一起发回
有用的资源
我在一个 Spring 引导应用程序中有多个伪装客户端。我正在使用 Controller Advice 来处理每个假装客户端的自定义异常。
这里我的控制器建议处理两个自定义异常(每个客户端一个:client1 和 client2):
@ControllerAdvice
public class ExceptionTranslator implements ProblemHandling {
@ExceptionHandler
public ResponseEntity<Problem> handleCustomClient1Exception(CustomException1 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
@ExceptionHandler
public ResponseEntity<Problem> handleCustomClient2Exception(CustomException2 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
}
我已经为 feign client1 实现了一个错误解码器。
public class ClientErrorDecoder implements ErrorDecoder {
final ObjectMapper mapper;
public ClientErrorDecoder() {
this.mapper = new ObjectMapper();
}
@Override
public Exception decode(String methodKey, Response response) {
ExceptionDTO exceptionDTO;
try {
exceptionDTO = mapper.readValue(response.body().asInputStream(), ExceptionDTO.class);
} catch (IOException e) {
throw new RuntimeException("Failed to process response body.", e);
}
return new CustomException1(exceptionDTO.getDetail(), exceptionDTO.getCode(), exceptionDTO.getTitle(), exceptionDTO.getStatus());
}
}
我还配置了 feign,以便为特定客户端使用该错误解码器,如下所示:
feign:
client:
config:
client1:
errorDecoder: feign.codec.ErrorDecoder.Default
我的问题是:处理多个客户端异常的最佳方法是什么?我应该使用相同的错误解码器并将它们的响应视为一般异常吗?或者我应该为每个假客户端创建一个错误解码器?
快速解答
如果您使用不同的 API,错误响应的格式将不同。因此,分别处理它们似乎是最好的方法。
备注
从你的例子来看,你似乎定义了一个自定义 ErrorDecoder
不被使用,因为您还在属性文件中配置了假装为您的 client1 使用默认错误解码器。
即使你在某处定义了一个 @Configuration
class 和你的自定义 ClientErrorDecoder
的 bean,
Spring Cloud documentation 提到配置属性优先于 @Configuration
注释
If we create both @Configuration bean and configuration properties, configuration properties will win. It will override @Configuration values. But if you want to change the priority to @Configuration, you can change feign.client.default-to-properties to false.
例子
这是一个假设的修剪配置,用于处理具有不同错误解码器的多个假客户端:
客户端 1: 您告诉 feign 为 client1
加载CustomFeignConfiguration
class 中定义的 bean
@FeignClient(name = "client1", configuration = {CustomFeignConfiguration.class})
public interface Client1 {...}
客户端 2:
Client2 将使用默认的 Feign ErrorDecoder
因为没有指定配置。 (将在错误时抛出 FeignException
)
@FeignClient(name = "client2")
public interface Client2 {...}
Configuration:这里要注意,如果在CustomFeignConfiguration
中加上@Configuration
,那么会使用ClientErrorDecoder
bean 对于每个加载的假客户端(取决于您的应用程序组件扫描行为)
public class CustomFeignConfiguration {
@Bean
public ClientErrorDecoder clientErrorDecoder(ObjectMapper objectMapper) {
return new ClientErrorDecoder(objectMapper);
}
}
此配置也可以使用属性文件完成。
旁注
在我看来,您甚至不需要控制器建议。如果您使用 Spring Web @ResponseStatus
注释,您可以判断应该将哪个 HTTP 状态代码与您的自定义 ErrorDecoder
.
有用的资源