FeignClient抛异常而非返回错误状态ResponseEntity的解决方法
我明白你遇到的困扰:明明声明FeignClient方法返回ResponseEntity<T>,但服务端返回400这类非2xx状态码时,程序直接抛出FeignException,根本走不到你处理ResponseEntity的逻辑。这是因为Feign默认的ErrorDecoder会把所有非2xx响应转换成异常抛出,哪怕你声明了返回ResponseEntity。
下面给你两种可行的解决方案,你可以根据自己的场景选择:
方案一:自定义ErrorDecoder适配ResponseEntity返回类型
我们可以写一个自定义的ErrorDecoder,让它判断当前调用的Feign方法是否返回ResponseEntity,如果是,就把响应交给ResponseEntityDecoder处理,最终返回包含错误状态码的ResponseEntity,而不是抛出异常。
步骤1:修改FeignClient的配置类
在你的OauthFeignClient.Conf类中,注入ObjectFactory<HttpMessageConverters>并添加自定义ErrorDecoder的Bean:
@Configuration class Conf { @Value("${oauth.client.password}") String oauthClientPassword; @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(); } @Bean public Contract feignContract() { return new SpringMvcContract(); } @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("web-client", oauthClientPassword); } @Bean public ErrorDecoder errorDecoder() { return new CustomResponseEntityErrorDecoder(messageConverters); } }
步骤2:实现自定义ErrorDecoder
添加一个静态内部类,处理ResponseEntity类型的方法:
static class CustomResponseEntityErrorDecoder implements ErrorDecoder { private final ErrorDecoder defaultErrorDecoder = new ErrorDecoder.Default(); private final ResponseEntityDecoder responseEntityDecoder; public CustomResponseEntityErrorDecoder(ObjectFactory<HttpMessageConverters> messageConverters) { this.responseEntityDecoder = new ResponseEntityDecoder(new SpringDecoder(messageConverters)); } @Override public Exception decode(String methodKey, Response response) { try { // 解析当前Feign方法的元数据,获取返回类型 MethodMetadata metadata = MethodMetadata.parse(Feign.configKey(OauthFeignClient.class, methodKey)); Method method = metadata.method(); Type returnType = method.getGenericReturnType(); // 判断返回类型是否是ResponseEntity if (returnType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) returnType; if (ResponseEntity.class.equals(parameterizedType.getRawType())) { // 用ResponseEntityDecoder解析响应,确保能封装成ResponseEntity responseEntityDecoder.decode(response, returnType); // 返回包含原始响应的FeignException,让Spring的解码器最终转换成ResponseEntity return FeignException.errorStatus(methodKey, response); } } } catch (IOException e) { // 解析失败时,交给默认ErrorDecoder处理 return defaultErrorDecoder.decode(methodKey, response); } // 非ResponseEntity类型的方法,沿用默认异常处理逻辑 return defaultErrorDecoder.decode(methodKey, response); } }
方案二:升级Spring Cloud版本(更简单)
如果你的Spring Cloud版本比较旧(比如低于2020.0.x系列),可能存在ResponseEntity返回类型处理不完善的问题。升级到较新的版本(如2020.0.x或更高)后,默认情况下,返回ResponseEntity的Feign方法会自动返回包含非2xx状态码的ResponseEntity对象,不需要额外配置ErrorDecoder。
不过要注意:如果服务端返回的400响应格式不符合你produces指定的application/json,解码器可能还是会抛出异常,这时你需要调整produces属性,或者在自定义ErrorDecoder中兼容这种情况。
内容的提问来源于stack exchange,提问作者ch4mp

