您好,登錄后才能下訂單哦!
這篇文章主要介紹“Feign怎么調用接口解決內部異常的問題”,在日常操作中,相信很多人在Feign怎么調用接口解決內部異常的問題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Feign怎么調用接口解決內部異常的問題”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
當使用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); } }
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; } }
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); }
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; } }
@FeignClient("guli-cart") public interface CartFenignService { @GetMapping("/currentUserCartItems") List<OrderItemVo> getCurrentUserCartItems(); }// 這樣去掉接口時其實Feign在底層是一個全新的requst所有請求頭就沒有了
@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);
這樣就可以了~
到此,關于“Feign怎么調用接口解決內部異常的問題”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。