Spring 官方最終仍是按捺不住推出了本身的網關組件:Spring Cloud Gateway ,相比以前咱們使用的 Zuul(1.x) 它有哪些優點呢?Zuul(1.x) 基於 Servlet,使用阻塞 API,它不支持任何長鏈接,如 WebSockets,Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。java
Spring Cloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基於 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在爲微服務架構提供一種簡單有效的統一的 API 路由管理方式。web
Spring Cloud Gateway 做爲 Spring Cloud 生態系統中的網關,目標是替代 Netflix Zuul,其不只提供統一的路由方式,而且基於 Filter 鏈的方式提供了網關基本的功能,例如:安全,監控/指標,和限流。正則表達式
相關概念:spring
org.springframework.cloud.gateway.filter.GatewayFilter
的實例,咱們可使用它修改請求和響應。工做流程:瀏覽器
客戶端向 Spring Cloud Gateway 發出請求。若是 Gateway Handler Mapping 中找到與請求相匹配的路由,將其發送到 Gateway Web Handler。Handler 再經過指定的過濾器鏈來將請求發送到咱們實際的服務執行業務邏輯,而後返回。 過濾器之間用虛線分開是由於過濾器可能會在發送代理請求以前(「pre」)或以後(「post」)執行業務邏輯。安全
Spring Cloud Gateway 的特徵:cookie
Spring Cloud Gateway 網關路由有兩種配置方式:架構
@Bean
自定義 RouteLocator,在啓動主類 Application 中配置這兩種方式是等價的,建議使用 yml 方式進配置。app
使用 Spring Cloud Finchley 版本,Finchley 版本依賴於 Spring Boot 2.0.6.RELEASE。curl
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
經測試 Finchley.RELEASE 有 bug 屢次請求會報空指針異常,SR2 是 Spring Cloud 的最新版本。
添加項目須要使用的依賴包
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
Spring Cloud Gateway 是使用 netty+webflux 實現所以不須要再引入 web 模塊。
咱們先來測試一個最簡單的請求轉發。
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: neo_route
uri: http://www.ityouknow.com
predicates:
- Path=/spring-cloud
各字段含義以下:
上面這段配置的意思是,配置了一個 id 爲 neo_route 的路由規則,當訪問地址 http://localhost:8080/spring-cloud
時會自動轉發到地址:http://www.ityouknow.com/spring-cloud
。配置完成啓動項目便可在瀏覽器訪問進行測試,當咱們訪問地址http://localhost:8080/spring-cloud
時會展現頁面展現以下:
證實頁面轉發成功。
轉發功能一樣能夠經過代碼來實現,咱們能夠在啓動類 GateWayApplication 中添加方法 customRouteLocator()
來定製轉發規則。
@SpringBootApplication public class GateWayApplication { public static void main(String[] args) { SpringApplication.run(GateWayApplication.class, args); } @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("path_route", r -> r.path("/about") .uri("http://ityouknow.com")) .build(); } }
上面配置了一個 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 來源於 Java 8,是 Java 8 中引入的一個函數,Predicate 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默認方法來將 Predicate 組合成其餘複雜的邏輯(好比:與,或,非)。能夠用於接口請求參數校驗、判斷新老數據是否有變化須要進行更新操做。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性實現了各類路由匹配規則,有經過 Header、請求參數等不一樣的條件來進行做爲條件匹配到對應的路由。網上有一張圖總結了 Spring Cloud 內置的幾種 Predicate 的實現。
說白了 Predicate 就是爲了實現一組匹配規則,方便讓請求過來找到對應的 Route 進行處理,接下來咱們接下 Spring Cloud GateWay 內置幾種 Predicate 的使用。
Predicate 支持設置一個時間,在請求進行轉發的時候,能夠經過判斷在這個時間以前或者以後進行轉發。好比咱們如今設置只有在2019年1月1日纔會轉發到個人網站,在這以前不進行轉發,我就能夠這樣配置:
spring:
cloud:
gateway:
routes:
- id: time_route
uri: http://ityouknow.com
predicates:
- After=2018-01-20T06:06:06+08:00[Asia/Shanghai]
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,以下:
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://ityouknow.com
predicates:
- Before=2018-01-20T06:06:06+08:00[Asia/Shanghai]
就表示在這個時間以前能夠進行路由,在這時間以後中止路由,修改完以後重啓項目再次訪問地址http://localhost:8080
,頁面會報 404 沒有找到地址。
除過在時間以前或者以後外,Gateway 還支持限制路由請求在某一個時間段範圍內,可使用 Between Route Predicate 來實現。
spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://ityouknow.com
predicates:
- Between=2018-01-20T06:06:06+08:00[Asia/Shanghai], 2019-01-20T06:06:06+08:00[Asia/Shanghai]
這樣設置就意味着在這個時間段內能夠匹配到此路由,超過這個時間段範圍則不會進行匹配。經過時間匹配路由的功能很酷,能夠用在限時搶購的一些場景中。
Cookie Route Predicate 能夠接收兩個參數,一個是 Cookie name ,一個是正則表達式,路由規則會經過獲取對應的 Cookie name 值和正則表達式去匹配,若是匹配上就會執行路由,若是沒有匹配上則不執行。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://ityouknow.com
predicates:
- Cookie=ityouknow, kee.e
使用 curl 測試,命令行輸入:
curl http://localhost:8080 --cookie "ityouknow=kee.e"
則會返回頁面代碼,若是去掉--cookie "ityouknow=kee.e"
,後臺彙報 404 錯誤。
Header Route Predicate 和 Cookie Route Predicate 同樣,也是接收 2 個參數,一個 header 中屬性名稱和一個正則表達式,這個屬性值和正則表達式匹配則執行。
spring:
cloud:
gateway:
routes:
- id: header_route
uri: http://ityouknow.com
predicates:
- Header=X-Request-Id, \d+
使用 curl 測試,命令行輸入:
curl http://localhost:8080 -H "X-Request-Id:666666"
則返回頁面代碼證實匹配成功。將參數-H "X-Request-Id:666666"
改成-H "X-Request-Id:neo"
再次執行時返回404證實沒有匹配。
Host Route Predicate 接收一組參數,一組匹配的域名列表,這個模板是一個 ant 分隔的模板,用.
號做爲分隔符。它經過參數中的主機地址做爲匹配規則。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://ityouknow.com
predicates:
- Host=**.ityouknow.com
使用 curl 測試,命令行輸入:
curl http://localhost:8080 -H "Host: www.ityouknow.com"
curl http://localhost:8080 -H "Host: md.ityouknow.com"
經測試以上兩種 host 都可匹配到 host_route 路由,去掉 host 參數則會報 404 錯誤。
能夠經過是 POST、GET、PUT、DELETE 等不一樣的請求方式來進行路由。
spring:
cloud:
gateway:
routes:
- id: method_route
uri: http://ityouknow.com
predicates:
- Method=GET
使用 curl 測試,命令行輸入:
# curl 默認是以 GET 的方式去請求
curl http://localhost:8080
測試返回頁面代碼,證實匹配到路由,咱們再以 POST 的方式請求測試。
# curl 默認是以 GET 的方式去請求
curl -X POST http://localhost:8080
返回 404 沒有找到,證實沒有匹配上路由
Path Route Predicate 接收一個匹配路徑的參數來判斷是否走路由。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://ityouknow.com
predicates:
- Path=/foo/{segment}
若是請求路徑符合要求,則此路由將匹配,例如:/foo/1 或者 /foo/bar。
使用 curl 測試,命令行輸入:
curl http://localhost:8080/foo/1
curl http://localhost:8080/foo/xx
curl http://localhost:8080/boo/xx
通過測試第一和第二條命令能夠正常獲取到頁面返回值,最後一個命令報404,證實路由是經過指定路由來匹配。
Query Route Predicate 支持傳入兩個參數,一個是屬性名一個爲屬性值,屬性值能夠是正則表達式。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://ityouknow.com
predicates:
- Query=smile
這樣配置,只要請求中包含 smile 屬性的參數便可匹配路由。
使用 curl 測試,命令行輸入:
curl localhost:8080?smile=x&id=2
通過測試發現只要請求彙總帶有 smile 參數即會匹配路由,不帶 smile 參數則不會匹配。
還能夠將 Query 的值以鍵值對的方式進行配置,這樣在請求過來時會對屬性值和正則進行匹配,匹配上纔會走路由。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://ityouknow.com
predicates:
- Query=keep, pu.
這樣只要當請求中包含 keep 屬性而且參數值是以 pu 開頭的長度爲三位的字符串纔會進行匹配和路由。
使用 curl 測試,命令行輸入:
curl localhost:8080?keep=pub
測試能夠返回頁面代碼,將 keep 的屬性值改成 pubx 再次訪問就會報 404,證實路由須要匹配正則表達式纔會進行路由。
Predicate 也支持經過設置某個 ip 區間號段的請求才會路由,RemoteAddr Route Predicate 接受 cidr 符號(IPv4 或 IPv6 )字符串的列表(最小大小爲1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子網掩碼)。
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: http://ityouknow.com
predicates:
- RemoteAddr=192.168.1.1/24
能夠將此地址設置爲本機的 ip 地址進行測試。
curl localhost:8080
果請求的遠程地址是 192.168.1.10,則此路由將匹配。
上面爲了演示各個 Predicate 的使用,咱們是單個單個進行配置測試,其實能夠將各類 Predicate 組合起來一塊兒使用。
例如:
spring:
cloud:
gateway:
routes:
- id: host_foo_path_headers_to_httpbin
uri: http://ityouknow.com
predicates:
- Host=**.foo.org
- Path=/headers
- Method=GET
- Header=X-Request-Id, \d+
- Query=foo, ba.
- Query=baz
- Cookie=chocolate, ch.p
- After=2018-01-20T06:06:06+08:00[Asia/Shanghai]
各類 Predicates 同時存在於同一個路由時,請求必須同時知足全部的條件才被這個路由匹配。
一個請求知足多個路由的謂詞條件時,請求只會被首個成功匹配的路由轉發