Feign調用全局異常處理解決方案
異常信息形如:
TestService#addRecord(ParamVO) failed and no fallback available.;
對於failed and no fallback available.這種異常信息,是因為項目開啟瞭熔斷:
feign.hystrix.enabled: true
當調用服務時拋出瞭異常,卻沒有定義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); } }
定義系統的異常類
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); } }
統一異常攔截轉換對應的異常信息返回前端
public class ResultSet { /** * 返回的狀態碼 */ private Integer resultCode; /** * 返回的消息 */ private String resultMsg; /** * 返回的數據 */ 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("系統異常,請聯系系統開發人員進行處理", e); } resultSet.setResultCode(-1); resultSet.setResultMsg(e.getMessage()); resultSet.setData(null); } return resultSet; }
這樣就能完成瞭feign接收異常處理的自定義異常信息!
統一處理@FeignClient調用接口異常—-原樣拋出
第三方系統調用我方系統@FeignClient接口時報錯
com.netflix.hystrix.exception.HystrixRuntimeException: WorkFlowTaskOperateService#processWorkFlowTaskSyncCallback(TaskProcessDTO) failed and no fallback available.
我方系統出現FeignException.
第三方調用者拋出的異常:HystrixRuntimeException
一檢查我們系統確實沒有指定fallback和configuration,並且調用方開啟瞭feign.hystrix.enabled: true
@FeignClient(value = "taxplan-workflow")
修改方法:
第三方調用在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());
實現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, "參數不能為空"), PARAM_FORMAT_ILLEGAL(4003, "參數格式錯誤"), REQUEST_DATA_DUPLICATION(4004, "重復請求"), REQUEST_DATA_ERROR(4005, "請求數據錯誤"), REQUEST_DATA_NOT_MATCH(4006, "請求數據不一致"), RECORD_NOT_EXIST(5001, "記錄不存在"), RECORD_EXISTED(5002, "記錄已存在"), RECORD_ILLEGAL_STATE(5003, "數據異常"), BALANCE_NOT_ENOUGH(5103, "餘額不足"), CALL_INNER_ERROR(5800, "調用內部服務接口異常"), THIRD_PART_ERROR(5801, "調用第三方接口異常"), SYSTEM_ERROR(9999, "系統異常"); public final int code; public final String defaultMessage; private ExceptionCode(int code, String defaultMessage) { this.code = code; this.defaultMessage = defaultMessage; } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- FeignClient服務器拋出異常客戶端處理方案
- SpringCloud feign服務熔斷下的異常處理操作
- SpringBoot中如何統一接口返回與全局異常處理詳解
- 解決Feign獲取異常信息的處理方案
- SpringBoot 統一公共返回類的實現