Feign調(diào)用全局異常處理解決方案
異常信息形如:
TestService#addRecord(ParamVO) failed and no fallback available.;
對于failed and no fallback available.這種異常信息,是因為項目開啟了熔斷:
feign.hystrix.enabled: true
當調(diào)用服務(wù)時拋出了異常,卻沒有定義fallback方法,就會拋出上述異常。由此引出了第一個解決方式。
解決方案:
自定義Feign解析器:
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.crecgec.baseboot.jsoncore.exception.BaseException; import feign.Response; import feign.Util; import feign.codec.ErrorDecoder; import org.springframework.context.annotation.Configuration; import java.io.IOException; @Configuration public class FeignErrorDecoder implements ErrorDecoder { @Override public Exception decode(String methodKey, Response response) { try { // 這里直接拿到我們拋出的異常信息 String message = Util.toString(response.body().asReader()); try { JSONObject jsonObject = JSONObject.parseObject(message); return new BaseException(jsonObject.getString("resultMsg"), jsonObject.getInteger("resultCode")); } catch (JSONException e) { e.printStackTrace(); } } catch (IOException ignored) { } return decode(methodKey, response); } }
定義系統(tǒng)的異常類
public class BaseException extends RuntimeException { private int status ; public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public BaseException() { } public BaseException(String message, int status) { super(message); this.status = status; } public BaseException(String message) { super(message); } public BaseException(String message, Throwable cause) { super(message, cause); } public BaseException(Throwable cause) { super(cause); } public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
統(tǒng)一異常攔截轉(zhuǎn)換對應(yīng)的異常信息返回前端
public class ResultSet { /** * 返回的狀態(tài)碼 */ private Integer resultCode; /** * 返回的消息 */ private String resultMsg; /** * 返回的數(shù)據(jù) */ private Object data; public ResultSet() { } public ResultSet(Integer resultCode, String resultMsg) { this.resultCode = resultCode; this.resultMsg = resultMsg; } public ResultSet(Integer resultCode, String resultMsg, Object data) { this.resultCode = resultCode; this.resultMsg = resultMsg; this.data = data; } public Integer getResultCode() { return resultCode; } public void setResultCode(Integer resultCode) { this.resultCode = resultCode; } public String getResultMsg() { return resultMsg; } public void setResultMsg(String resultMsg) { this.resultMsg = resultMsg; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
全局異常類處理配置:
@ExceptionHandler(value = BaseException.class) public ResultSet defaultErrorHandler(HttpServletRequest req, HttpServletResponse resp, BaseException e) { ResultSet resultSet = new ResultSet(); if (e.getStatus() == 400) { resultSet.setResultCode(-1); resultSet.setResultMsg(e.getMessage()); resultSet.setData(null); resp.setStatus(400); } else { resp.setStatus(500); if(logger.isErrorEnabled()){ logger.error("系統(tǒng)異常,請聯(lián)系系統(tǒng)開發(fā)人員進行處理", e); } resultSet.setResultCode(-1); resultSet.setResultMsg(e.getMessage()); resultSet.setData(null); } return resultSet; }
這樣就能完成了feign接收異常處理的自定義異常信息!
統(tǒng)一處理@FeignClient調(diào)用接口異常----原樣拋出
第三方系統(tǒng)調(diào)用我方系統(tǒng)@FeignClient接口時報錯
com.netflix.hystrix.exception.HystrixRuntimeException: WorkFlowTaskOperateService#processWorkFlowTaskSyncCallback(TaskProcessDTO) failed and no fallback available.
我方系統(tǒng)出現(xiàn)FeignException.
第三方調(diào)用者拋出的異常:HystrixRuntimeException
一檢查我們系統(tǒng)確實沒有指定fallback和configuration,并且調(diào)用方開啟了feign.hystrix.enabled: true
@FeignClient(value = "taxplan-workflow")
修改方法:
第三方調(diào)用在Application.java添加處理Feign異常的全局處理方法
@Bean public Feign.Builder feignBuilder() { return Feign.builder().requestInterceptor(new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { Map<String, String> customHeaders = WebUtils.getCustomHeaders(); customHeaders.forEach((k, v) -> { requestTemplate.header(k, v); }); } }).errorDecoder(new CustomErrorDecoder()); }
這里使用了RequestInterceptor攔截器,可以定制請求頭,如果不想定制,可以改為
return Feign.builder().errorDecoder(new CustomErrorDecoder());
實現(xiàn)ErrorDecoder接口,其中ExceptionCode是枚舉類.
public Exception decode(String methodKey, Response response) { if (response.status() >= 400 && response.status() <= 499) { return new BaseBizException(ExceptionCode.CALL_INNER_ERROR, "Client error.httpStatusCode:" + response.status()); } else { if (response.status() >= 500 && response.status() <= 599 && response.body() != null) { try { String content = CharStreams.toString(new InputStreamReader(response.body().asInputStream(), StandardCharsets.UTF_8)); Map responseBody = (Map) JSONObject.parseObject(content, Map.class); if (responseBody.containsKey("code")) { return new BaseBizException(responseBody.get("code").toString(), Objects.toString(responseBody.get("msg"))); } } catch (Exception var5) { } } return new BaseBizException(ExceptionCode.CALL_INNER_ERROR); } }
ExceptionCode枚舉類如下:可以自定義增加刪除
public enum ExceptionCode { ILLEGAL_STATE(4001, "非法訪問"), PARAM_REQUIRED(4002, "參數(shù)不能為空"), PARAM_FORMAT_ILLEGAL(4003, "參數(shù)格式錯誤"), REQUEST_DATA_DUPLICATION(4004, "重復(fù)請求"), REQUEST_DATA_ERROR(4005, "請求數(shù)據(jù)錯誤"), REQUEST_DATA_NOT_MATCH(4006, "請求數(shù)據(jù)不一致"), RECORD_NOT_EXIST(5001, "記錄不存在"), RECORD_EXISTED(5002, "記錄已存在"), RECORD_ILLEGAL_STATE(5003, "數(shù)據(jù)異常"), BALANCE_NOT_ENOUGH(5103, "余額不足"), CALL_INNER_ERROR(5800, "調(diào)用內(nèi)部服務(wù)接口異常"), THIRD_PART_ERROR(5801, "調(diào)用第三方接口異常"), SYSTEM_ERROR(9999, "系統(tǒng)異常"); public final int code; public final String defaultMessage; private ExceptionCode(int code, String defaultMessage) { this.code = code; this.defaultMessage = defaultMessage; } }
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot 接收POST、json、文本數(shù)據(jù)的方法 附示例
這篇文章主要介紹了Springboot 接收POST、json、文本數(shù)據(jù)實踐,如果把 json 作為參數(shù)傳遞,我們可以使用 @requestbody 接收參數(shù),將數(shù)據(jù)直接轉(zhuǎn)換成對象,本文通過示例代碼介紹的非常詳細,需要的朋友可以參考下2023-10-10Java框架Quartz中API、Jobs和Trigger詳解
這篇文章主要介紹了Java框架Quartz中API、Jobs和Trigger詳解,JobDetail?對象是在將?job?加入?scheduler?時,由客戶端程序(你的程序)創(chuàng)建的,它包含?job?的各種屬性設(shè)置,以及用于存儲?job?實例狀態(tài)信息的?JobDataMap,需要的朋友可以參考下2023-11-11詳解spring-cloud與netflixEureka整合(注冊中心)
這篇文章主要介紹了詳解spring-cloud與netflixEureka整合(注冊中心),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-02-02利用Spring Boot如何開發(fā)REST服務(wù)詳解
這篇文章主要給大家介紹了關(guān)于利用Spring Boot如何開發(fā)REST服務(wù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2017-12-12springboot根據(jù)實體類生成表的實現(xiàn)方法
本文介紹了如何通過SpringBoot工程引入SpringDataJPA,并通過實體類自動生成數(shù)據(jù)庫表的過程,包括常見問題解決方法,感興趣的可以了解一下2024-09-09