Zuul的內置過濾器詳解(源碼解析)
從技術角度來說,Zuul的的核心就是一系列的過濾器。這些過濾器都實現了ZuulFilter接口。
Zuul的過濾器ZuulFilter與Spring的過濾器Filter有什麼區別?
一,ZuulFilter
ZuulFilter是一個抽象類。ZuulFilter實現了IZuulFilter接口、Comparable接口。
繼承ZuulFilter的類需要實現下面4個方法:
filterType():過濾器類型,可選值有4個,pre、route、post、error。
filterOrder():過濾器執行的優先級。當某種類型的過濾器有多個時,根據優先級依次執行。
shouldFilter():判斷過濾器是否需要執行。可以通過這個方法來限制過濾器的執行條件。
run():過濾器的具體執行邏輯。
二,pre過濾器
1,ServletDetectionFilter
ServletDetectionFilter:檢查請求是否經過DispatcherServlet的轉發。如果經過,則把
isDispatcherServletRequest置爲true,否則置爲false。
2,FormBodyWrapperFilter
filterOrder=-1
解析表單數據,併爲請求重新編碼。
3,DebugFilter
調試過濾器。源碼很簡單:
RequestContext ctx =
RequestContext.getCurrentContext();
ctx.setDebugRouting(true);
ctx.setDebugRequest(true);
該過濾器可以控制debug日誌的打印。如果需要打印debug日誌,我們可以這樣設置:
zuul.debug.request=true
這樣就可以打印相關的debug日誌,這對於我們定位zuul的問題有幫助。例如下面這段代碼:
if(RequestContext.getCurrentContext().debugRouting()){…}
Zuul會根據debugRoute來判斷是否打印這條日誌信息。
4,PreDecorationFilter
根據提供的RouteLocator,設置路由地址。還會設置這些屬性:requestURI、proxy、
retryable、forward.to、serviceId、Host等屬性。
5,TracePreZuulFilter
結合Sleuth實現鏈路追蹤功能。
6,Servlet30WrapperFilter
對原始請求進行包裝,爲什麼要包裝一下呢?包裝就是爲了拿過來,然後有必要的話方便擴展。
原始請求:HttpServletRequest
包裝後請求:Servlet30RequestWrapper
三,route過濾器
1,SendForwardFilter
這個過濾器的優先級是500,在route過濾器的實現中是最大的。也就是說三個route過濾器,SendForwardFilter最後執行。
SendForwardFilter過濾器的執行需要滿足下面的條件:
RequestContext中包含屬性:forward.to
RequestContext中包含屬性:sendForwardFilter.ran並且值爲true
SendForwardFilter是根據forward.to配置的url來轉發請求的。
RequestDispatcher dispatcher = cxt.getRequest().getRequestDispatcher(path);
if(dispatcher != null){
ctx.set("sendForwardFilter.ran", true);
if(!ctx.getResponse().isCommited()){
dispatcher.forward(cxt.getRequest(), ctx.getResponse());
ctx.getResponse().flushBuffer();
}
}
SendForwardFilter與下面兩種過濾器的區別是:SendForwardFilter使用ApplicationDispatcher來轉發請求。
2,RibbonRoutingFilter
RibbonRoutingFilter過濾器的執行需要滿足下面的條件:
RequestContext中不包含屬性:routeHost
RequestContext中包含屬性:serviceId
RequestContext中包含屬性:sendZuulResponse並且值爲true
RibbonRoutingFilter與SendForwardFilter的區別是RibbonRoutingFilter使用robbin來請求微服務。
3,SimpleHostRoutingFilter
SimpleHostRoutingFilter過濾器的執行需要滿足下面的條件:
RequestContext中包含屬性:routeHost
RequestContext中包含屬性:sendZuulResponse並且值爲true
SimpleHostRoutingFilter與RibbonRoutingFilter的區別是:RibbonRoutingFilter使用robbin來請求微服務,而SimpleHostRoutingFilter是通過HttpClient來轉發請求。
四,post過濾器
1,SendResponseFilter
SendResponseFilter主要做兩件事:
// 從RequestContext中取出微服務的響應結果,然後封裝到HttpServletResponse中。
this.addResponseHeaders();
// 把響應結果寫入輸出流,發送給客戶端。
this.writeResponse()
五,error過濾器
1,SendErrorFilter
轉發請求到/error。這裏的路徑是可配置的。
首先會從ZuulException中拿到具體的異常信息:
RequestContext ctx = RequestContext.getCurrentContext();
ZuulException exception = this.findZuulException(ctx.getThrowable());
HttpServletRequest request = ctx.getRequest();
然後把異常信息放到request,最後轉發請求到指定路徑。
RequestDispatcher dispatcher = request.getRequestDispatcher(this.errorPath);
if(dispatcher != null){
ctx.set("sendErrorFilter.ran", true);
if(!ctx.getResponse().isCommited()){
dispatcher.forward(request, ctx.getResponse())
}
六,Zuul內置的特殊過濾器
zuul還提供了一類特殊的過濾器,分別爲:StaticResponseFilter和SurgicalDebugFilter
StaticResponseFilter:StaticResponseFilter允許從Zuul本身生成響應,而不是將請求轉發到源。也就是說,Zuul接收到請求後,直接返回給客戶端,不再轉發給其他微服務。
SurgicalDebugFilter:SurgicalDebugFilter允許將特定請求路由到分隔的調試集羣或主機。
六,Zuul過濾器的優先級
ServletDetectionFilter:-3
Servlet30WrapperFilter:-2
FormBodyWrapperFilter:-1
SendErrorFilter:0
DebugFilter:1
PreDecorationFilter:5
RibbonRoutingFulter:10
SimpleHostRoutingFilter:100
SendForwardFilter:500
SendResponseFilter:1000