Spring Cloud源碼分析(四)Zuul:核心過濾器

https://mp.weixin.qq.com/s/xYU8e6uM5e7bdebI7qjuSwhtml

經過以前博客發佈的《Spring Cloud構建微服務架構(五)服務網關》一文,相信你們對於Spring Cloud Zuul已經有了一個基礎的認識。經過前文的介紹,咱們對於Zuul的第一印象一般是這樣的:它包含了對請求的路由和過濾兩個功能,其中路由功能負責將外部請求轉發到具體的微服務實例上,是實現外部訪問統一入口的基礎;而過濾器功能則負責對請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎。然而實際上,路由功能在真正運行時,它的路由映射和請求轉發都是由幾個不一樣的過濾器完成的。其中,路由映射主要經過pre類型的過濾器完成,它將請求路徑與配置的路由規則進行匹配,以找到須要轉發的目標地址;而請求轉發的部分則是由route類型的過濾器來完成,對pre類型過濾器得到的路由地址進行轉發。因此,過濾器能夠說是Zuul實現API網關功能最爲核心的部件,每個進入Zuul的HTTP請求都會通過一系列的過濾器處理鏈獲得請求響應並返回給客戶端。spring

下面,咱們就經過本文來詳細瞭解一下Spring Cloud Zuul的過濾器!如下內容節選自《Spring Cloud微服務實戰》,稍作加工。微信

過濾器

在Spring Cloud Zuul中實現的過濾器必須包含4個基本特徵:過濾類型、執行順序、執行條件、具體操做。這些元素看着彷佛很是的熟悉,實際上它就是ZuulFilter接口中定義的四個抽象方法:架構

1
2
3
4
5
6
7
String filterType();

int filterOrder();

boolean shouldFilter();

Object run();

它們各自的含義與功能總結以下:app

  • filterType:該函數須要返回一個字符串來表明過濾器的類型,而這個類型就是在HTTP請求過程當中定義的各個階段。在Zuul中默認定義了四種不一樣生命週期的過濾器類型,具體以下:
  • pre:能夠在請求被路由以前調用。
  • routing:在路由請求時候被調用。
  • post:在routing和error過濾器以後被調用。
  • error:處理請求時發生錯誤時被調用。
  • filterOrder:經過int值來定義過濾器的執行順序,數值越小優先級越高。
  • shouldFilter:返回一個boolean類型來判斷該過濾器是否要執行。咱們能夠經過此方法來指定過濾器的有效範圍。
  • run:過濾器的具體邏輯。在該函數中,咱們能夠實現自定義的過濾邏輯,來肯定是否要攔截當前的請求,不對其進行後續的路由,或是在請求路由返回結果以後,對處理結果作一些加工等。

請求生命週期

上一節中,對於Spring Cloud Zuul中的過濾器類型filterType,咱們已經作過一些簡單的介紹,Zuul默認定義了四個不一樣的過濾器類型,它們覆蓋了一個外部HTTP請求到達API網關,直到返回請求結果的所有生命週期。下圖源自Zuul的官方WIKI中關於請求生命週期的圖解,它描述了一個HTTP請求到達API網關以後,如何在各個不一樣類型的過濾器之間流轉的詳細過程。
Spring Cloud源碼分析(四)Zuul:核心過濾器
從上圖中,咱們能夠看到,當外部HTTP請求到達API網關服務的時候,首先它會進入第一個階段pre,在這裏它會被pre類型的過濾器進行處理,該類型的過濾器主要目的是在進行請求路由以前作一些前置加工,好比請求的校驗等。在完成了pre類型的過濾器處理以後,請求進入第二個階段routing,也就是以前說的路由請求轉發階段,請求將會被routing類型過濾器處理,這裏的具體處理內容就是將外部請求轉發到具體服務實例上去的過程,當服務實例將請求結果都返回以後,routing階段完成,請求進入第三個階段post,此時請求將會被post類型的過濾器進行處理,這些過濾器在處理的時候不只能夠獲取到請求信息,還能獲取到服務實例的返回信息,因此在post類型的過濾器中,咱們能夠對處理結果進行一些加工或轉換等內容。另外,還有一個特殊的階段error,該階段只有在上述三個階段中發生異常的時候纔會觸發,可是它的最後流向仍是post類型的過濾器,由於它須要經過post過濾器將最終結果返回給請求客戶端(實際實現上還有一些差異,後續介紹)。ide

核心過濾器

在Spring Cloud Zuul中,爲了讓API網關組件能夠更方便的上手使用,它在HTTP請求生命週期的各個階段默認地實現了一批覈心過濾器,它們會在API網關服務啓動的時候被自動地加載和啓用。咱們能夠在源碼中查看和了解它們,它們定義於spring-cloud-netflix-core模塊的org.springframework.cloud.netflix.zuul.filters包下。
Spring Cloud源碼分析(四)Zuul:核心過濾器函數

如上圖所示,在默認啓用的過濾器中包含了三種不一樣生命週期的過濾器,這些過濾器都很是重要,能夠幫助咱們理解Zuul對外部請求處理的過程,以及幫助咱們如何在此基礎上擴展過濾器去完成自身系統須要的功能。下面,咱們將逐個地對這些過濾器作一些詳細的介紹:微服務

pre過濾器

  • ServletDetectionFilter:它的執行順序爲-3,是最早被執行的過濾器。該過濾器老是會被執行,主要用來檢測當前請求是經過Spring的DispatcherServlet處理運行,仍是經過ZuulServlet來處理運行的。它的檢測結果會以布爾類型保存在當前請求上下文的isDispatcherServletRequest參數中,這樣在後續的過濾器中,咱們就能夠經過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-Forwarded-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關閉對這些頭域的添加動做。

《Spring Cloud實戰小貼士:Zuul處理Cookie和重定向》 一文中提到的加載敏感頭信息加入到忽略頭信息的操做調用就在PreDecorationFilter過濾器中實現。源碼分析

route過濾器

  • RibbonRoutingFilter:它的執行順序爲10,是route階段第一個執行的過濾器。該過濾器只對請求上下文中存在serviceId參數的請求進行處理,即只對經過serviceId配置路由規則的請求生效。而該過濾器的執行邏輯就是面向服務路由的核心,它經過使用Ribbon和Hystrix來向服務實例發起請求,並將服務實例的請求結果返回。
  • SimpleHostRoutingFilter:它的執行順序爲100,是route階段第二個執行的過濾器。該過濾器只對請求上下文中存在routeHost參數的請求進行處理,即只對經過url配置路由規則的請求生效。而該過濾器的執行邏輯就是直接向routeHost參數的物理地址發起請求,從源碼中咱們能夠知道該請求是直接經過httpclient包實現的,而沒有使用Hystrix命令進行包裝,因此這類請求並無線程隔離和斷路器的保護。
  • SendForwardFilter:它的執行順序爲500,是route階段第三個執行的過濾器。該過濾器只對請求上下文中存在forward.to參數的請求進行處理,即用來處理路由規則中的forward本地跳轉配置。post

    post過濾器

  • SendErrorFilter:它的執行順序爲0,是post階段第一個執行的過濾器。該過濾器僅在請求上下文中包含error.status_code參數(由以前執行的過濾器設置的錯誤編碼)而且尚未被該過濾器處理過的時候執行。而該過濾器的具體邏輯就是利用請求上下文中的錯誤信息來組織成一個forward到API網關/error錯誤端點的請求來產生錯誤響應。
  • SendResponseFilter:它的執行順序爲1000,是post階段最後執行的過濾器。該過濾器會檢查請求上下文中是否包含請求響應相關的頭信息、響應數據流或是響應體,只有在包含它們其中一個的時候就會執行處理邏輯。而該過濾器的處理邏輯就是利用請求上下文的響應信息來組織須要發送回客戶端的響應內容。

這裏不列出具體代碼了,讀者可自行根據類名來查看源碼瞭解詳細處理過程。下圖是對上述過濾器根據順序、名稱、功能、類型作了綜合的整理,能夠幫助咱們在自定義過濾器或是擴展過濾器的時候用來參考並全面地考慮整個請求生命週期的處理過程。
Spring Cloud源碼分析(四)Zuul:核心過濾器

本文節選自《Spring Cloud微服務實戰》,轉載請註明出處

相關文章:

  • Spring Cloud實戰小貼士:Zuul處理Cookie和重定向
  • Netflix Zuul與Nginx的性能對比
  • Spring Cloud Zuul實現動態路由

活動推薦:Spring Cloud技術沙龍 - 北京站
活動時間:2017年 5 月 6 日 13:00-17:00

活動地點:北京市海淀區上地五街開拓路 11 號福道大廈

活動議程

Agenda

13:00-13:40 簽到

14:00-14:30 王鴻飛: Spring Cloud 在新浪商業產品中的實戰應用

14:30-15:00 許進:Spring Cloud Zuul 與網關中間件

15:00-15:30 劉思賢:基於 Spring Cloud 的微服務實踐

15:30-16:00 現場抽獎 & 茶歇

16:00-16:30 張英磊:Spring Cloud 在雲計算 SaaS 中的實戰經驗分享

16:30-17:00 程天亮:Spring Boot 在鏈家網實踐

報名請至:http://www.hdb.com/party/rrt4b.html

SpringCloud新書推薦

Spring Cloud源碼分析(四)Zuul:核心過濾器
Spring Cloud源碼分析(四)Zuul:核心過濾器
版權聲明

本文采用 CC BY 3.0 CN協議 進行許可。 可自由轉載、引用,但需署名做者且註明文章出處。如轉載至微信公衆號,請在文末添加做者公衆號二維碼。
長按指紋
一鍵關注
Spring Cloud源碼分析(四)Zuul:核心過濾器
Spring Cloud源碼分析(四)Zuul:核心過濾器

相關文章
相關標籤/搜索