Feign调用接口解决处理内部异常的问题
程序员文章站
2022-06-25 10:00:43
问题描述:当使用feign调用接口,出现400~500~的接口问题时。会出错feign:feignexception。(因为是错误,只能用catch throwable,不可使用catch excep...
问题描述:
当使用feign调用接口,出现400~500~的接口问题时。会出错feign:feignexception。(因为是错误,只能用catch throwable,不可使用catch exception捕获异常)导致程序无法继续运行。
问题原因:
由于feign默认的错误处理类是funfeignfallback会throw new afsbaseexceptio导致外部无法捕获异常。
package com.ruicar.afs.cloud.common.core.feign; 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); } }
问题解决:自定义feignfallback异常处理:
1.自定义异常处理 invoiceapifeignfallbackfactory
package com.ruicar.afs.cloud.invoice.factory; import com.ruicar.afs.cloud.invoice.fallback.invoiceapifeignfallback; import com.ruicar.afs.cloud.invoice.feign.invoiceapifeign; import feign.hystrix.fallbackfactory; import org.springframework.stereotype.component; @component public class invoiceapifeignfallbackfactory implements fallbackfactory<invoiceapifeign> { @override public invoiceapifeign create(throwable throwable) { invoiceapifeignfallback invoiceapifeignfallback = new invoiceapifeignfallback(); invoiceapifeignfallback.setcause(throwable); return invoiceapifeignfallback; } }
2.feign调用 invoiceapifeignfallbackfactory
package com.ruicar.afs.cloud.invoice.feign; import com.alibaba.fastjson.jsonobject; import com.ruicar.afs.cloud.common.core.feign.annotations.afsfeignclear; import com.ruicar.afs.cloud.invoice.dto.invoicecheckdto; import com.ruicar.afs.cloud.invoice.factory.invoiceapifeignfallbackfactory; import io.swagger.annotations.apioperation; import org.springframework.cloud.openfeign.feignclient; import org.springframework.web.bind.annotation.postmapping; import org.springframework.web.bind.annotation.requestbody; import org.springframework.web.bind.annotation.requestheader; import java.util.map; /** * @description: 发票验证接口 * @author: rongji.zhang * @date: 2020/8/14 10:32 */ @feignclient(name = "invoice", url = "${com.greatwall.systems.invoice-system.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.实现自定义报错处理
package com.ruicar.afs.cloud.invoice.fallback; import com.alibaba.fastjson.jsonobject; import com.ruicar.afs.cloud.invoice.dto.invoicecheckdto; import com.ruicar.afs.cloud.invoice.feign.invoiceapifeign; import lombok.setter; import lombok.extern.slf4j.slf4j; import org.springframework.stereotype.component; import java.util.map; /** * @author fzero * @date 2019-01-24 */ @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; } }
feign远程调用失败-----丢请求头
@feignclient("guli-cart") public interface cartfenignservice { @getmapping("/currentusercartitems") list<orderitemvo> getcurrentusercartitems(); }// 这样去掉接口时其实feign在底层是一个全新的requst所有请求头就没有了
解决办法使用feign远程掉用拦截器,在远程请求是先创建拦截器
@bean("requestinterceptor") public requestinterceptor requestinterceptor() { return new requestinterceptor() { @override public void apply(requesttemplate template) { /** * 把以前的cookie放到新请求中去 原理就是运用了同一线程数据共享 threadlocal */ servletrequestattributes attributes = (servletrequestattributes) requestcontextholder.getrequestattributes(); httpservletrequest request = attributes.getrequest(); string cookie = request.getheader("cookie"); template.header("cookie", cookie); } }; }
但是上面的办法只能解决同意线程问题,在多线程下还是会丢失请求头
多线程下解决办法:
requestattributes requestattributes = requestcontextholder.getrequestattributes();
把请求单独拿出来给每个线程单独
requestcontextholder.setrequestattributes(requestattributes);
这样就可以了~
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
推荐阅读
-
解决vue中使用Axios调用接口时出现的ie数据处理问题
-
思考才能有效的解决问题----
-
思考才能有效的解决问题----
-
解决angularjs前后端分离调用接口传递中文时中文乱码的问题
-
数据插入到mysql数据库出现编码异常处理问题的解决办法
-
安防摄像机网页无插件直播方案EasyNVR关于接口调用出现401 Unauthorized问题的解决方法
-
工作纪实_13-SpringCloud本地调试Feign调用出现的诡异404问题,不走寻常的解决方案
-
解决feign接口返回泛型设置属性为null的问题
-
Feign调用接口解决处理内部异常的问题
-
解决vue中使用Axios调用接口时出现的ie数据处理问题