系统需要统一格式化返回调用异常的错误信息,所以编写了一个配置类实现了ErrorDecoder的接口,然后再@FeignClient的configuration加上了这个配置类,之前用得好好的,突然有一天不生效了,在这里记录排查处理过程。
1.首先查看到源码,feign.SynchronousMethodHandler#executeAndDecode
在1处发起请求之后,如果响应抛出的是IOException则直接返回了,不会调用到3处的自定义异常处理。
2.对于服务没有启动的情况,原生的异常类是UnknownHostException,在这里可能开启了重试,需要关掉,配置如下
spring:
cloud:
loadbalancer:
retry:
# 关闭自动重试,开启会导致feign ErrorDecoder配置失效
enabled: false
3.对于接口超时,这里抛出SocketTimeoutException确实是IOException的子类,不想每个FallbackFactory都加上这段判断处理逻辑怎么办呢,可以使用AOP对这个方法进行切入统一处理
@Slf4j
@Aspect
@Component
public class FeignExceptionAspect {
public FeignExceptionAspect(){}
@Pointcut("execution(* com.hyp.*.api.factory.*.create(..))")
public void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
Object obj = args[0];
if (obj == null) {
return;
}
Throwable throwable = (Throwable)obj;
if (throwable instanceof SocketTimeoutException || throwable instanceof RetryableException) {
log.error("接口超时 {}", throwable.getMessage());
throw new ServiceException("接口超时", HttpStatus.REQUEST_TIMEOUT.value());
} else if (throwable instanceof UnknownHostException) {
log.error("服务不可用 {}", throwable.getMessage());
throw new ServiceException("服务不可用", HttpStatus.SERVICE_UNAVAILABLE.value());
}
}
}