How Feign calls the interface to handle internal exceptions

Problem description: When using feign to call the interface, an interface problem of 400~500~ occurs. An error occurs: FeignException. (Because it is an error, you can only use catch Throwable, and you cannot use catch Exception to catch exceptions.) As a result, the program cannot continue to run.

Cause of the problem: Since feign's default error handling class is FunFeignFallback, it will throw new AfsBaseExceptio, causing exceptions that cannot be caught externally.

import com.alibaba.fastjson.JSONObject;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import feign.FeignException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;

import java.lang.reflect.Method;
import java.util.Objects;

@Data
@AllArgsConstructor
@Slf4j
public class FunFeignFallback<T> implements MethodInterceptor {
    private final Class<T> targetType;
    private final String targetName;
    private final Throwable cause;

    private static byte JSON_START = '{';

    @Nullable
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String errorMessage = cause.getMessage();
        if (!(cause instanceof FeignException)) {
            log.error("FunFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage);
            log.error("feign调用失败", cause);
            return IResponse.fail("请求失败,请稍后再试");
        }
        int status = ((FeignException.FeignClientException) this.cause).status();
        boolean isAuthFail = (status==426||status==403||status==401)&&"afs-auth".equals(targetName);
        FeignException exception = (FeignException) cause;
        if(isAuthFail){
            log.warn("授权失败==========原始返回信息:[{}]",exception.contentUTF8());
        }else {
            log.error("FunFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage);
            log.error("", cause);
            log.error("原始返回信息{}",exception.contentUTF8());
        }
        if(method.getReturnType().equals(Void.class)){
            throw new AfsBaseException("接口调用失败");
        }
        if(method.getReturnType().equals(IResponse.class)){
            if(exception instanceof FeignException.Forbidden){
                return IResponse.fail("没有权限").setCode("403");
            }
            if(exception instanceof FeignException.NotFound){
                return IResponse.fail("请求路径不存在").setCode("404");
            }
            if(exception instanceof FeignException.BadRequest){
                return IResponse.fail("参数错误").setCode("400");
            }

            if(exception.content()==null||exception.content().length==0){
                return IResponse.fail("请求失败,请稍后再试");
            }
            if(JSON_START==exception.content()[0]){
                return JSONObject.parseObject(exception.content(),IResponse.class);
            }else{
                return IResponse.fail(exception.contentUTF8());
            }
        }else{
            try {
                if(method.getReturnType().equals(String.class)){
                    return exception.contentUTF8();
                }else if(method.getReturnType().equals(JSONObject.class)){
                    if(JSON_START==exception.content()[0]){
                        return JSONObject.parseObject(exception.content(), JSONObject.class);
                    }
                }else if(!method.getReturnType().equals(Object.class)){
                    return JSONObject.parseObject(exception.content(), method.getReturnType());
                }
                if(JSON_START==exception.content()[0]){
                    JSONObject jsonObject = JSONObject.parseObject(exception.content(), JSONObject.class);
                    if(jsonObject.containsKey("code")&&jsonObject.containsKey("msg")) {
                        return jsonObject.toJavaObject(IResponse.class);
                    }
                }
            }catch (Throwable e){}
            throw new AfsBaseException("接口调用失败");
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        FunFeignFallback<?> that = (FunFeignFallback<?>) o;
        return targetType.equals(that.targetType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(targetType);

    }

}

Problem Solved: Customized feignFallback exception handling:

1. Custom exception handling InvoiceApiFeignFallbackFactory

@Component
public class InvoiceApiFeignFallbackFactory implements FallbackFactory<InvoiceApiFeign> {
    @Override
    public InvoiceApiFeign create(Throwable throwable) {
        InvoiceApiFeignFallback invoiceApiFeignFallback = new InvoiceApiFeignFallback();
        invoiceApiFeignFallback.setCause(throwable);
        return invoiceApiFeignFallback;
    }
}

2.feign calls InvoiceApiFeignFallbackFactory

/**
 * @description:
 * @author:
 * @date: 2020/8/14 10:32
 */
@FeignClient(name = "invoice", url = "${}" ,fallbackFactory = InvoiceApiFeignFallbackFactory.class)
public interface InvoiceApiFeign {
    /**
     *
     * @param dto
     * @return
     */
    @ApiOperation("获取业务数据API接口")
    @PostMapping(value = "/vi/check")
    @AfsFeignClear(true)//通过此注解防止添加内部token
    JSONObject InvoiceCheck(@RequestBody InvoiceCheckDto dto, @RequestHeader Map<String, String> headers);
}

3. Implement custom error reporting

/**
 * @author 
 * @date 
 */
@Slf4j
@Component
public class InvoiceApiFeignFallback implements InvoiceApiFeign {

    @Setter
    private Throwable cause;

    /**
     * @param dto
     * @param headers
     * @return
     */
    @Override
    public JSONObject InvoiceCheck(InvoiceCheckDto dto, Map<String, String> headers) {
        log.error("feign 接口调用失败", cause);
        return null;
    }
}

Guess you like

Origin blog.csdn.net/qq_42857603/article/details/109810568