天天看點

Zuul過濾器詳解

Zuul過濾器

在Spring Cloud Zuul中實作的過濾器必須包含4個基本特征:過濾類型、執行順序、執行條件、具體操作。這些元素看起來非常熟悉,實際上它就是ZuulFilter接口中定義的4個抽象方法:

abstract public String filterType();

abstract public int filterOrder();

boolean shouldFilter();

Object run();
           
  • filterType

    :該函數需要傳回一個字元串來代表過濾器的類型,而這個類型就是在HTTP請求過程中定義的各個階段。在Zuul中預設定義了4種不同生命周期的過濾器類型,具體如下所示。
    • pre:可以在請求被路由之前調用。
    • routing:在路由請求時被調用。
    • post:在routing和error過濾器之後被調用。
    • error: 處理請求時發生錯誤時被調用。
  • filterOrder

    :通過int值來定義過濾器的執行順序,數值越小優先級越高。
  • shouldFilter

    : 傳回一個boolean值來判斷該過濾器是否要執行。我們可以通過此方法來指定過濾器的有效範圍。
  • run

    :過濾器的具體邏輯。在該函數中,我們可以實作自定義的過濾邏輯,來确定

    是否要攔截目前的請求,不對其進行後續的路由,或是在請求路由傳回結果之後,對處理結果做一些加工等。

請求生命周期

Zuul過濾器詳解

從上圖中我們可以看到,當外部HTTP請求到達API網關服務的時候,首先它會進入第一個階段pre,在這裡它會被pre類型的過濾器進行處理,該類型過濾器的主要目的是在進行請求路由之前做一些前置加工,比如請求的校驗等。在完成了pre類型的過濾器處理之後,請求進入第二個階段routing,也就是之前說的路由請求轉發階段,請求将會被routing類型過濾器處理。這裡的具體處理内容就是将外部請求轉發到具體服務執行個體上去的過程,當服務執行個體将請求結果都傳回之後,routing 階段完成,請求進入第三個階段post。此時請求将會被post類型的過濾器處理,這些過濾器在處理的時候不僅可以擷取到請求資訊,還能擷取到服務執行個體的傳回資訊,是以在post類型的過濾器中,我們可以對處理結果進行一些加工或轉換等内容。另外,還有一個特殊的階段error,該階段隻有在上述三個階段中發生異常的時候才會觸發,但是它的最後流向還是post類型的過濾器,

因為它需要通過post過濾器将最終結果傳回給請求用戶端(對于error 過濾器的處理,在Spring Cloud Zuul的過濾鍊中實際上有一些不同,後續我們在介紹核心過濾器時會做詳細分析)。

核心過濾器

在Spring Cloud Zuul中,為了讓API網關元件可以被更友善地使用,它在HTTP請求生命周期的各個階段預設實作了一批核心過濾器,它們會在API網關服務啟動的時候被自動加載和啟用。我們可以在源碼中檢視和了解它們,它們定義于

spring-cloud-netflix-core

子產品的

org.springframework.cloud.netflix.zuul.filters

包下。

如下圖所示,在預設啟用的過濾器中包含三種不同生命周期的過濾器,這些過濾器都非常重要,可以幫助我們了解Zuul對外部請求處理的過程,以及幫助我們在此基礎上擴充過濾器去完成自身系統需要的功能。下面,我們将逐個對這些過濾器做詳細的介紹。

Zuul過濾器詳解

pre過濾器

ServletDetectionFilter:

它的

執行順序為-3,是最先被執行的過濾器

該過濾器總是會被執行,主要用來檢測目前請求是通過Spring的DispatcherServlet處理運作的,還是通過ZuulServlet來處理運作的。

它的檢測結果會以布爾類型儲存在目前請求上下文的

isDi spatcherServletRequest

參數中,這樣在後續的過濾器中,我們就可以通過

RequestUtils. isDispatcherServletRequest () 和RequestUtils. isZuulServletRequest ()方法來判斷請求處理的源頭,以實作後續不同的處理機制

一般情況下,發送到API網關的外部請求都會被Spring的DispatcherServlet 處理,

除了通過/zuul/*路徑通路的請求會繞過DispatcherServlet,被ZuulServlet處理,主要用來應對處理大檔案上傳的情況

。另外,對于ZuulServlet的通路路徑/zuul/*,我們可以通過zuul. servletPath參數來進行修改。

Servlet30WrapperFilter:

它的

執行順序為-2,是第二個執行的過濾器

目前的實作會對所有請求生效,主要為了将原始的HttpServletRequest 包裝成Servlet30RequestWrapper對象。

FormBodyWrapperFilter:

它的

執行順序為-1,是第三個執行的過濾器

該過濾器僅對兩類請求生效,第一類是Content-Type 為

application/x-www-form-urlencoded

的請求,第二類是Content-Type為

multipart/ form-data并且是由Spring 的DispatcherServlet 處理的請求

(用到了ServletDetectionFilter的處理結果)。而該過濾器的主要目的是将符合要求的請求體包裝成FormBodyRequestWrapper對象。

DebugFilter:

它的

執行順序為1,是第四個執行的過濾器

該過濾器會

根據配置參數zuul.debug.request和請求中的debug參數來決定是否執行過濾器中的操作

而它的具體操作内容則是将目前請求上下文中的debugRouting 和debugRequest參數設定為true。由于在同一個請求的不同生命周期中都可以通路到這兩個值,是以我們在後續的各個過濾器中可以利用這兩個值來定義一些debug資訊,這樣當線上環境出現問題的時候,可以通過請求參數的方式來激活這些debug資訊以幫助分析問題。另外,對于請求參數中的debug參數,我們也可以通過

zuul.debug.parameter

來進行自定義。

PreDecorationFilter:

它的

執行順序為5,是pre階段最後被執行的過濾器

該過濾器會

判斷目前請求上下文中是否存在forward.to和serviceId參數,如果都不存在,那麼它就會執行具體過濾器的操作

(如果有一個存在的話;說明目前請求已經被處理過了,因為這兩個資訊就是根據目前請求的路由資訊加載進來的)。

而它的具體操作内容就是為目前請求做一些預處理,比如,進行路由規則的比對、在請求上下文中設定該請求的基本資訊以及将路由比對結果等一些設定資訊等,這些資訊将是後續過濾器進行處理的重要依據,我們可以通過

RequestContext.getCurrentContext ()

來通路這些資訊。另外,我們還可以在該實作中找到一些對HTTP頭請求進行處理的邏輯,其中包含了一些耳熟能詳的頭域,比如X-Forwa rded-Host、X-Forwarded-Port。另外,對于這些頭域的記錄是通過

zuul.addProxyHeaders

參數進行控制的,而這個參數的預設值為true,是以.Zuul在請求跳轉時預設會為請求增加X-Forwarded-*頭域,包括X-Forwarded-Host、X-Forwarded-Port、 X-Forwarded-For、 X-Forwarded-Prefix、X- Forwarded- Proto。也可以通過設定

zuul.addProxyHeaders=false關閉對這些頭域的添加動作。

route過濾器

RibbonRoutingFilter:

它的

執行順序為10,是route階段第一個執行的過濾器。

該過濾器隻對請求上下文中存在serviceId參數的請求進行處理,即隻對通過serviceId配置路由規則的請求生效。

而該過濾器的執行邏輯就是面向服務路由的核心,它通過使用Ribbon和Hystrix來向服務執行個體發起請求,并将服務執行個體的請求結果傳回。

SimpleHostRoutingFilter:

它的

執行順序為100,是route階段第二個執行的過濾器

該過濾器

隻對請求上下文中存在routeHost參數的請求進行處理,即隻對通過url配置路由規則的請求生效。

而該過濾器的執行邏輯就是直接向routeHost參數的實體位址發起請求,從源碼中我們可以知道該

請求是直接通過httpclient包實作的,而沒有使用Hystrix指令進行包裝,是以這類請求并沒有線程隔離和斷路器的保護。

SendForwardFilter:

它的

執行順序為500,是route階段第三個執行的過濾器。

該過濾器

隻對請求上下文中存在forward.to參數的請求進行處理,即用來處理路由規則中的forward本地跳轉配置

post過濾器

SendErrorFilter:

它的

執行順序為0,是post階段第-一個執行的過濾器

該過濾器

僅在請求上下文中包含error.status_code 參數(由之前執行的過濾器設定的錯誤編碼)并且還沒有被該過濾器處理過的時候執行

。而該過濾器的具體邏輯就是利用請求上下文中的錯誤資訊來組成一個forward到API網關/error錯誤端點的請求來産生錯誤響應。

SendResponseFilter:

它的

執行順序為1000,是post階段最後執行的過濾器

該過濾器會檢查請求上下文中是否包含請求響應相關的頭資訊、響應資料流或是響應體,隻有在包含它們其中一個的時候執行處理邏輯。而該過濾器的處理邏輯就是利用請求上下文的響應資訊來組織需要發送回用戶端的響應内容。

下圖對上述過濾器根據順序、名稱、功能、類型做了綜合整理,可以幫助我們在自定義過濾器或是擴充過濾器的時候用來參考并全面地考慮整個請求生命周期的處理過程。

Zuul過濾器詳解

繼續閱讀