如何为多个 feign 客户端实现错误解码器

Yan*_*988 7 spring-boot feign

我在 Spring Boot 应用程序中有多个伪装客户端。我正在使用控制器建议来处理每个假客户端的自定义异常。

这里我的控制器建议处理两个自定义异常(每个客户端一个: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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

我已经为 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());


}
Run Code Online (Sandbox Code Playgroud)

}

我还配置了 feign 为该特定客户端使用该错误解码器,如下所示:

feign:
client:
    config:
        client1:
            errorDecoder: feign.codec.ErrorDecoder.Default
Run Code Online (Sandbox Code Playgroud)

我的问题是:处理多个假客户端异常的最佳方法什么?我应该使用相同的错误解码器并将它们的响应视为通用异常吗?或者我应该为每个假客户端创建一个错误解码器?

use*_*803 10

快速回答

如果您使用不同的 API,错误响应的格式将不会相同。因此,分别处理它们似乎是最好的方法。

评论

从您的示例来看,您似乎定义了一个ErrorDecoder可能未使用的自定义项,因为您还在属性文件中将 feign 配置为对 client1 使用默认错误解码器。即使您在@Configuration某处为您的自定义定义了一个带有 bean的类ClientErrorDecoderSpring Cloud 文档也提到配置属性优先于@Configuration注释

如果我们同时创建@Configuration bean 和配置属性,配置属性将获胜。它将覆盖@Configuration 值。但是如果你想把优先级改成@Configuration,你可以把feign.client.default-to-properties改成false。

例子

这是一个假设的修剪配置,用于处理具有不同错误解码器的多个 feign 客户端:

Client1:您告诉 feign 加载CustomFeignConfiguration类中为 client1定义的 bean

@FeignClient(name = "client1", configuration = {CustomFeignConfiguration.class})
public interface Client1 {...}
Run Code Online (Sandbox Code Playgroud)

Client2:Client2 将使用默认 Feign,ErrorDecoder因为没有指定配置。(会抛出一个FeignException错误)

@FeignClient(name = "client2")
public interface Client2 {...}
Run Code Online (Sandbox Code Playgroud)

配置:这里要小心,如果你添加@ConfigurationCustomFeignConfiguration,那么ClientErrorDecoderbean 将用于每个加载的假客户端(取决于你的应用程序组件扫描行为)

public class CustomFeignConfiguration {
    @Bean
    public ClientErrorDecoder clientErrorDecoder(ObjectMapper objectMapper) {
        return new ClientErrorDecoder(objectMapper);
    }
}
Run Code Online (Sandbox Code Playgroud)

这个配置也可以用属性文件来完成。

旁注

在我看来,您甚至不需要控制器建议。如果使用 Spring Web@ResponseStatus注释,则可以通过自定义抛出的异常主体来判断应发送回哪个 HTTP 状态代码ErrorDecoder.

有用的资源