1. 程式人生 > >Spring Cloud Alibaba系列(四)使用gateway作為服務閘道器

Spring Cloud Alibaba系列(四)使用gateway作為服務閘道器

## 什麼是閘道器 > 在微服務架構裡,服務的粒度被進一步細分,各個業務服務可以被獨立的設計、開發、測試、部署和管理。這時,各個獨立部署單元可以用不同的開發測試團隊維護,可以使用不同的程式語言和技術平臺進行設計,這就要求必須使用一種語言和平臺無關的服務協議作為各個單元間的通訊方式。 換句話說就是閘道器為所有的請求提供了統一的入口,方便我們對服務請求和響應做統一管理。 ## 為什麼要用閘道器 API 閘道器是一個處於應用程式或服務(提供 REST API 介面服務)之前的系統,用來管理授權、訪問控制和流量限制等,這樣 REST API 介面服務就被 API 閘道器保護起來,對所有的呼叫者透明。 ![](https://i.loli.net/2020/05/06/UkVGCHc68yYTzjO.png) ## 什麼是gateway > Spring Cloud Gateway是Spring官方基於Spring 5.0,Spring Boot 2.0和Project Reactor等技術開發的閘道器,Spring Cloud Gateway旨在為微服務架構提供一種簡單而有效的統一的API路由管理方式。Spring Cloud Gateway作為Spring Cloud生態系中的閘道器,目標是替代ZUUL,其不僅提供統一的路由方式,並且基於Filter鏈的方式提供了閘道器基本的功能,例如:安全,監控/埋點,和限流等。 ## gateway工作原理 ![](https://i.loli.net/2020/05/06/UXRmb5Cclh9Wjrz.png) > 客戶端向Spring Cloud閘道器發出請求。如果閘道器處理程式對映確定請求與路由匹配,則將其傳送到閘道器Web處理程式。該處理程式執行通過特定於請求的過濾器鏈傳送請求。過濾器由虛線分隔的原因是,過濾器可以在傳送代理請求之前或之後執行邏輯。執行所有“前置”過濾器邏輯,然後發出代理請求。發出代理請求後,將執行“後”過濾器邏輯。 ## 路由規則 路由和過濾器是gateway中非常重要的兩個概念,gateway本身提供了非常豐富的路由規則和多種過濾器來適配我們的需求。gateway提供了11種路由規則,分別是: - 後置路由謂詞工廠 該謂詞匹配在當前日期時間之後發生的請求。引數名為 After - 前置路由謂詞工廠 該謂詞匹配當前日期時間之前發生的請求。引數名為 Before - 時間段路由謂詞工廠 該謂詞匹配在datetime1之後和datetime2之前發生的請求。引數名為 Between - cookie路由謂詞工廠 該謂詞匹配具有給定名稱的cookie,並且值匹配正則表示式。引數名為 Cookie - 標頭路由謂詞工廠 該謂詞與具有給定名稱的標頭匹配,並且值與正則表示式匹配。引數名為 Header - 主機路由謂詞工廠 該謂詞是指由路由進行匹配,匹配多個路由時用,隔開。引數名為 Host - 方法路由謂詞工廠 該引數是一個或多個要匹配的HTTP方法。引數名為 Method - 路徑路由謂詞工廠 該謂詞是指在請求路徑上加一個字首,以此來匹配。引數名為 Path - 查詢路由謂詞工廠 - RemoteAddr路由謂詞工廠 - 重量路線謂詞工廠 其中,我們比較常用的就是**路徑路由謂詞工廠**,配合StripPrefix GatewayFilter工廠,實現我們的路由匹配轉發。 路徑路由謂詞工廠配置如下: ```java spring: cloud: gateway: discovery: locator: enabled: true # 開啟從註冊中心動態建立路由的功能,利用微服務名稱進行路由 routes: # 路由id,建議配合服務名 - id: demo_route #匹配路由名 uri: lb://demo-provider predicates: # 斷言,路徑相匹配的進行路由 - Path=/demo/** ``` 配置的含義就是,如果請求路徑中是/demo/**,則轉發到demo-provider服務。 ## 閘道器過濾器 在spring cloud gateway 2.2.2.RELEASE版本中,已經預設實現了30種過濾器。 | 序號 | 過濾器工廠 | 作用 | 引數 | | :--: | ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | 1 | AddRequestHeader | 為原始請求新增Header | Header的名稱及值 | | 2 | AddRequestParameter | 為原始請求新增請求引數 | 引數名稱及值 | | 3 | AddResponseHeader | 為原始響應新增Header | Header的名稱及值 | | 4 | DedupeResponseHeader | 剔除響應頭中重複的值 | 需要去重的Header名稱及去重策略 | | 5 | Hystrix | 為路由引入Hystrix的斷路器保護 | HystrixCommand的名稱 | | 6 | CircuitBreaker | 為路由引入Resilience4J斷路器保護 | CircuitBreaker的名稱 | | 7 | FallbackHeaders | 為fallbackUri的請求頭中新增具體的異常資訊 | Header的名稱 | | | MapRequestHeader | 更新原始請求中的Header | Header的值 | | 9 | PrefixPath | 為原始請求頭新增字首 | 字首路徑 | | 10 | PreserveHostHeader | 為請求新增preserverHostHeader=true的屬性,路由過濾器會檢查該屬性以決定是否要傳送原始的host | 無 | | 11 | RequestRateLimiter | 用於對請求限流,限流演算法為令牌桶 | keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus | | 12 | RedirectTo | 將原始請求重定向到指定的url | http狀態碼及重定向的url | | 13 | RemoveHopByHopHeadersFilter | 為原始請求刪除IETF組織規定的一系列Header | 預設就會啟用,可以通過配置指定僅刪除哪些Header | | 14 | RemoveRequestHeader | 為原始請求刪除某個Header | Header名稱 | | 15 | RemoveResponseHeader | 為原始響應刪除某個Header | Header名稱 | | 16 | RewritePath | 重寫原始的請求路徑 | 原始路徑正則表示式以及重寫後路徑的正則表示式 | | | RewriteLocationResponseHeader | 重寫響應頭的`Location` 的值 | | | 18 | RewriteResponseHeader | 重寫原始響應中的某個Header | Header名稱,值的正則表示式,重寫後的值 | | 19 | SaveSession | 在轉發請求之前,強制執行`WebSession::save`操作 | 無 | | 20 | SecureHeaders | 為原始響應新增一系列起安全作用的響應頭 | 無,支援修改這些安全響應頭的值 | | 21 | SetPath | 修改原始的請求路徑 | 修改後的值 | | 22 | SetRequestHeader | 修改原始請求中的某個Header的值 | Header名稱,修改後的值 | | 23 | SetResponseHeader | 修改原始響應中某個Header的值 | Header名稱,修改後的值 | | 24 | SetStatus | 修改原始響應的狀態碼 | HTTP 狀態碼,可以是數字,也可以是字串 | | 25 | StripPrefix | 用於截斷原始請求的路徑 | 使用數字表示要截斷的路徑的數量 | | 26 | Retry | 針對不同的響應進行重試 | retries、statuses、methods、series | | 27 | RequestSize | 設定允許接收最大請求包的大小。如果請求包大小超過設定的值,則返回 `413 Payload Too Large`設定允許接收最大請求包的大小。如果請求包大小超過設定的值,則返回 `413 Payload Too Large` | 請求包大小,單位為位元組,預設值為5M | | 28 | ModifyRequestBody | 在轉發請求之前修改原始請求體內容 | 修改後的請求體內容 | | 29 | ModifyResponseBody | 修改原始響應體的內容 | 修改後的響應體內容 | | 30 | Default | 為所有路由新增過濾器 | 過濾器工廠名稱及值 | 這裡比較常用的如第25種,配置如下: ```java spring: cloud: gateway: discovery: locator: enabled: true # 開啟從註冊中心動態建立路由的功能,利用微服務名稱進行路由 routes: # 路由id,建議配合服務名 - id: demo_route #匹配路由名 uri: lb://demo-provider predicates: # 斷言,路徑相匹配的進行路由 - Path=/demo/** filters: - StripPrefix=1 ``` 一般情況下我們配合path路由使用,這裡的意思是假如,我們的demo-provider服務種有一個/test的介面,實際上我們的請求路徑經過閘道器時應該時/demo/test,這樣就能把這個路由分發到demo-provider服務中,但是分發過去的路由是/demo/test,和我們實際的/test介面不一樣。這時候我們用StripPrefix=1,來擷取掉一級路由,這樣轉發過去的路由就是/test了。 ## 自定義閘道器過濾器 除了上面提供的30種過濾器外,我們還可以實現自定義的過濾器。 ### 1. 實現GatewayFilter介面和Ordered介面 gatewayFilter介面是為了實現請求過濾,ordered介面是為了給過濾器設定優先順序,值越大級別越低。 想要實現一個自定義的過濾器,無非就是兩個步驟:**1.實現過濾器,2.將過濾器新增到具體路由上。** ```java public class TokenGatewayFilter implements GatewayFilter, Ordered { @Override pub