天天看點

Spring Cloud 終于按捺不住推出了自己的服務網關 Gateway

Spring 官方最終還是按捺不住推出了自己的網關元件:Spring Cloud Gateway ,相比之前我們使用的 Zuul(1.x) 它有哪些優勢呢?Zuul(1.x) 基于 Servlet,使用阻塞 API,它不支援任何長連接配接,如 WebSockets,Spring Cloud Gateway 使用非阻塞 API,支援 WebSockets,支援限流等新特性

                                                                                                              Spring Cloud Gateway

Spring Cloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在為微服務架構提供一種簡單有效的統一的 API 路由管理方式。

Spring Cloud Gateway 作為 Spring Cloud 生态系統中的網關,目标是替代 Netflix Zuul,其不僅提供統一的路由方式,并且基于 Filter 鍊的方式提供了網關基本的功能,例如:安全,監控/名額,和限流。

相關概念:

·Route(路由):這是網關的基本建構塊。它由一個 ID,一個目标 URI,一組斷言和一組過濾器定義。如果斷言為真,則路由比對。

·Predicate(斷言):這是一個 Java 8 的 Predicate。輸入類型是一個 ServerWebExchange。我們可以使用它來比對來自 HTTP 請求的任何内容,例如 headers 或參數。

·Filter(過濾器):這是org.springframework.cloud.gateway.filter.GatewayFilter的執行個體,我們可以使用它修改請求和響應。

工作流程:

用戶端向 Spring Cloud Gateway 送出請求。如果 Gateway Handler Mapping 中找到與請求相比對的路由,将其發送到 Gateway Web Handler。Handler 再通過指定的過濾器鍊來将請求發送到我們實際的服務執行業務邏輯,然後傳回。

過濾器之間用虛線分開是因為過濾器可能會在發送代理請求之前(“pre”)或之後(“post”)執行業務邏輯。

Spring Cloud Gateway 的特征:

·基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0

·動态路由

·Predicates 和 Filters 作用于特定路由

·內建 Hystrix 斷路器

·內建 Spring Cloud DiscoveryClient

·易于編寫的 Predicates 和 Filters

·限流

·路徑重寫

                                                                                                                 快速上手

Spring Cloud Gateway 網關路由有兩種配置方式:

·在配置檔案 yml 中配置

·通過@Bean自定義 RouteLocator,在啟動主類 Application 中配置

這兩種方式是等價的,建議使用 yml 方式進配置。

使用 Spring Cloud Finchley 版本,Finchley 版本依賴于 Spring Boot 2.0.6.RELEASE。

添加項目需要使用的依賴包

Spring Cloud Gateway 是使用 netty+webflux 實作是以不需要再引入 web 子產品。

我們先來測試一個最簡單的請求轉發。

各字段含義如下:

id:我們自定義的路由 ID,保持唯一

uri:目标服務位址

predicates:路由條件,Predicate 接受一個輸入參數,傳回一個布爾值結果。該接口包含多種預設方法來将 Predicate 組合成其他複雜的邏輯(比如:與,或,非)。

filters:過濾規則,本示例暫時沒用。

上面這段配置的意思是,配置了一個 id 為 neo_route 的路由規則,當通路位址http://localhost:8080/spring-cloud時會自動轉發到位址:http://www.ityouknow.com/spring-cloud。配置完成啟動項目即可在浏覽器通路進行測試

轉發功能同樣可以通過代碼來實作,我們可以在啟動類 GateWayApplication 中添加方法 customRouteLocator() 來定制轉發規則。

上面配置了一個 id 為 path_route 的路由,當通路位址http://localhost:8080/about時會自動轉發到位址:http://www.ityouknow.com/about和上面的轉發效果一樣,隻是這裡轉發的是以項目位址/about格式的請求位址。

上面兩個示例中 uri 都是指向了我的個人網站,在實際項目使用中可以将 uri 指向對外提供服務的項目位址,統一對外輸出接口。

以上便是 Spring Cloud Gateway 最簡單的兩個請求示例,Spring Cloud Gateway 還有更多實用的功能接下來我們一一介紹。

                                                                                                                路由規則

Spring Cloud Gateway 的功能很強大,我們僅僅通過 Predicates 的設計就可以看出來,前面我們隻是使用了 predicates 進行了簡單的條件比對,其實 Spring Cloud Gataway 幫我們内置了很多 Predicates 功能。

Spring Cloud Gateway 是通過 Spring WebFlux 的HandlerMapping做為底層支援來比對到轉發路由,Spring Cloud Gateway 内置了很多 Predicates 工廠,這些 Predicates 工廠通過不同的 HTTP 請求參數來比對,多個 Predicates 工廠可以組合使用。

Predicate 介紹

Predicate 來源于 Java 8,是 Java 8 中引入的一個函數,Predicate 接受一個輸入參數,傳回一個布爾值結果。該接口包含多種預設方法來将 Predicate 組合成其他複雜的邏輯(比如:與,或,非)。可以用于接口請求參數校驗、判斷新老資料是否有變化需要進行更新操作。and--與、or--或、negate--非

在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性實作了各種路由比對規則,有通過 Header、請求參數等不同的條件來進行作為條件比對到對應的路由。網上有一張圖總結了 Spring Cloud 内置的幾種 Predicate 的實作。

說白了 Predicate 就是為了實作一組比對規則,友善讓請求過來找到對應的 Route 進行處理,接下來我們接下 Spring Cloud GateWay 内置幾種 Predicate 的使用。

通過時間比對

Predicate 支援設定一個時間,在請求進行轉發的時候,可以通過判斷在這個時間之前或者之後進行轉發。比如我們現在設定隻有在2019年1月1日才會轉發到我的網站,在這之前不進行轉發,我就可以這樣配置:

Spring 是通過 ZonedDateTime 來對時間進行的對比,ZonedDateTime 是 Java 8 中日期時間功能裡,用于表示帶時區的日期與時間資訊的類,ZonedDateTime 支援通過時區來設定時間,中國的時區是:Asia/Shanghai。

After Route Predicate 是指在這個時間之後的請求都轉發到目标位址。上面的示例是指,請求時間在 2018年1月20日6點6分6秒之後的所有請求都轉發到位址http://ityouknow.com。+08:00是指時間和UTC時間相差八個小時,時間地區為Asia/Shanghai。

添加完路由規則之後,通路位址http://localhost:8080會自動轉發到http://ityouknow.com。

Before Route Predicate 剛好相反,在某個時間之前的請求的請求都進行轉發。我們把上面路由規則中的 After 改為 Before,如下:

就表示在這個時間之前可以進行路由,在這時間之後停止路由,修改完之後重新開機項目再次通路位址http://localhost:8080,頁面會報 404 沒有找到位址。

除過在時間之前或者之後外,Gateway 還支援限制路由請求在某一個時間段範圍内,可以使用 Between Route Predicate 來實作。

這樣設定就意味着在這個時間段内可以比對到此路由,超過這個時間段範圍則不會進行比對。通過時間比對路由的功能很酷,可以用在限時搶購的一些場景中。

通過 Cookie 比對

Cookie Route Predicate 可以接收兩個參數,一個是 Cookie name ,一個是正規表達式,路由規則會通過擷取對應的 Cookie name 值和正規表達式去比對,如果比對上就會執行路由,如果沒有比對上則不執行。

使用 curl 測試,指令行輸入:

則會傳回頁面代碼,如果去掉--cookie "ityouknow=kee.e",背景彙報 404 錯誤。

通過 Header 屬性比對

Header Route Predicate 和 Cookie Route Predicate 一樣,也是接收 2 個參數,一個 header 中屬性名稱和一個正規表達式,這個屬性值和正規表達式比對則執行。

則傳回頁面代碼證明比對成功。将參數-H "X-Request-Id:666666"改為-H "X-Request-Id:neo"再次執行時傳回404證明沒有比對。

通過 Host 比對

Host Route Predicate 接收一組參數,一組比對的域名清單,這個模闆是一個 ant 分隔的模闆,用.号作為分隔符。它通過參數中的主機位址作為比對規則。

經測試以上兩種 host 均可比對到 host_route 路由,去掉 host 參數則會報 404 錯誤。

通過請求方式比對

可以通過是 POST、GET、PUT、DELETE 等不同的請求方式來進行路由。

測試傳回頁面代碼,證明比對到路由,我們再以 POST 的方式請求測試。

傳回 404 沒有找到,證明沒有比對上路由

通過請求路徑比對

Path Route Predicate 接收一個比對路徑的參數來判斷是否走路由。

如果請求路徑符合要求,則此路由将比對,例如:/foo/1 或者 /foo/bar。

經過測試第一和第二條指令可以正常擷取到頁面傳回值,最後一個指令報404,證明路由是通過指定路由來比對。

通過請求參數比對

Query Route Predicate 支援傳入兩個參數,一個是屬性名一個為屬性值,屬性值可以是正規表達式。

這樣配置,隻要請求中包含 smile 屬性的參數即可比對路由。

經過測試發現隻要請求彙總帶有 smile 參數即會比對路由,不帶 smile 參數則不會比對。

還可以将 Query 的值以鍵值對的方式進行配置,這樣在請求過來時會對屬性值和正則進行比對,比對上才會走路由。

這樣隻要當請求中包含 keep 屬性并且參數值是以 pu 開頭的長度為三位的字元串才會進行比對和路由。

測試可以傳回頁面代碼,将 keep 的屬性值改為 pubx 再次通路就會報 404,證明路由需要比對正規表達式才會進行路由。

通過請求 ip 位址進行比對

Predicate 也支援通過設定某個 ip 區間号段的請求才會路由,RemoteAddr Route Predicate 接受 cidr 符号(IPv4 或 IPv6 )字元串的清單(最小大小為1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 位址,16 是子網路遮罩)。

可以将此位址設定為本機的 ip 位址進行測試。

果請求的遠端位址是 192.168.1.10,則此路由将比對。

組合使用

上面為了示範各個 Predicate 的使用,我們是單個單個進行配置測試,其實可以将各種 Predicate 組合起來一起使用。

例如:

各種 Predicates 同時存在于同一個路由時,請求必須同時滿足所有的條件才被這個路由比對。

一個請求滿足多個路由的謂詞條件時,請求隻會被首個成功比對的路由轉發

總結

通過今天的學習發現 Spring Cloud Gateway 使用非常的靈活,可以根據不同的情況來進行路由分發,在實際項目中可以自由組合使用。同時 Spring Cloud Gateway 還有更多很酷的功能,比如 Filter 、熔斷和限流等,下次我們繼續學習 Spring Cloud Gateway 的進階功能。

歡迎工作一到五年的Java工程師朋友們加入Java填坑之路:860113481

群内提供免費的Java架構學習資料(裡面有高可用、高并發、高性能及分布式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!