Zuul包括兩部份內容:請求的路由和過濾。而實際上請求的路由也是經過過濾器實現的,例如理由映射主要經過pre類型的過濾器完成,它將請求路徑與配置的路由規則進行匹配,找到須要轉發的目標地址;請求轉發的部分則是由route類型的過濾器來完成的,對pre類型過濾器得到的路由地址進行轉發。因此過濾器時Zuul實現API網關功能最爲核心的部件,每個進入Zuul的Http請求都會通過一系列的過濾器處理鏈獲得請求響應並返回給客戶端。spring
過濾類型、執行順序、執行條件、具體操做app
過濾器類型 | 順序 | 過濾器 | 功能 |
---|---|---|---|
pre | -3 | ServletDetectionFilter | 標記處理Servlet的類型 |
pre | -2 | Servlet30WrapperFilter | 包裝HttpServletRequest請求 |
pre | -1 | FormBodyWrapperFilter | 包裝請求體 |
pre | 1 | DebugFilter | 標記調試標誌 |
pre | 5 | PreDecorationFilter | 處理請求上下文供後續使用 |
route | 10 | RibbonRoutingFilter | serviceId請求轉發 |
route | 100 | SimpleHostRoutingFilter | url請求轉發 |
route | 500 | SendForwordFilter | forward請求轉發 |
post | 0 | SendErrorFilter | 處理有錯誤的請求響應 |
post | 1000 | SendResponseFilter | 處理正常處理的請求響應 |
對於可預知異常處理,可使用SendErrorFilter處理
SendErrorFilter過濾器對異常處理的觸發條件是,異常信息必須包含error.status_code錯誤信息,因此在進行異常處理的時候須要在異常信息中添加error.status_code信息用來出發SendErrorFilter。分佈式
對於不可預知的異常須要使用全局異常處理,即便用ErrorFilter處理
在請求生命週期的pre、route、post三個階段中有異常拋出的時候都會進入error階段的處理,因此能夠建立一個error類型的過濾器來捕獲這些異常信息,並根據這些異常信息在請求上下文中注入須要返回給客戶端的錯誤描述。常見用法是,在try-catch中注入error信息,讓SendErrorFilter捕獲處理返回給客戶端,eg:ide
public class ErrorFilter extends ZuulFilter { private static final Logger log = LoggerFactory.getLogger(ErrorFilter.class); @Override public String filterType() { return "error"; } @Override public int filterOrder() { return 10; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); Throwable throwable = ctx.getThrowable(); log.error("this is a ErrorFilter:{}.", throwable.getCause().getMessage()); ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); ctx.set("error.exception", throwable.getCause()); return null; } }
第一種是在開發過程當中對異常的處理,第二種是對第一種的補充,防止意外異常發生post
try{ preRoute(); }catch(ZuulException e){ error(e); postRoute(); return; } try{ route(); }catch(ZuulException e){ error(e); postRoute(); return; } try{ postRoute(); }catch(ZuulException){ error(e); return; }
在pre、route過濾器調用過程當中,拋出異常都要通過error過濾器處理,而後再經過post返回客戶端。可是,**若是在post中出現了異常,由error過濾器處理後並不會再調用post階段的請求,這些error.*參數就不會被SendErrorFilter消費輸出,會形成異常泄露**。this
在error過濾器以後在加一層SendErrorFilter,用來執行post過濾器中拋出的異常url
public class ErrorExtFilter extends SendErrorFilter { @Override public String filterType() { return "error"; } @Override public int filterOrder() { return 30; } @Override public boolean shouldFilter() { //TODO return true; } }
那麼怎樣判斷過濾器來自於哪一個階段呢,須要重寫FilterProcessor核心過濾器類,在執行filter具體邏輯的方法processZuulFilter方法中對處理的filter進行標記調試
public class MarkFilterProcessor extends FilterProcessor { @Override public Object processZuulFilter(ZuulFilter filter) throws ZuulException { try { return super.processZuulFilter(filter); } catch (ZuulException e) { RequestContext ctx = RequestContext.getCurrentContext(); ctx.set("failed.filter", filter); throw e; } } }
在shouldFilter方法中進行判斷是否是post階段拋出的異常code
@Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); ZuulFilter failedFilter = (ZuulFilter) ctx.get("failed.filter"); if(failedFilter != null && failedFilter.filterType().equals("post")) { return true; } return false; }
最後在主類中調用FilterProcessor.setProcessor(new MarkFilterProcessor());啓動自定義的核心處理器orm
默認使用DefaultErrorAttributes做爲默認異常信息接口,若是有ErrorAttributes接口的實現類,則不適用默認的,而使用實現類
public class MessageErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map<String, Object> result = super.getErrorAttributes(requestAttributes, includeStackTrace); result.remove("exception"); return result; } }
public DefaultErrorAttributes errorAttributes() { return new MessageErrorAttributes(); }
zuul.<filtername>.<filtertype>.disable=true
使用spring cloud config分佈式配置中心實現application.properties/application.yarm動態加載