Spring
在因Netflix
開源流產(chǎn)事件后潭辈,在不斷的更換Netflix
相關(guān)的組件,比如:Eureka
止潮、Zuul
、Feign
钞楼、Ribbon
等喇闸,Zuul
的替代產(chǎn)品就是SpringCloud Gateway
,這是Spring
團(tuán)隊研發(fā)的網(wǎng)關(guān)組件询件,可以實現(xiàn)限流燃乍、安全認(rèn)證、支持長連接等新特性宛琅。
Spring Cloud Gateway
Spring Cloud Gateway
是SpringCloud
的全新子項目刻蟹,該項目基于Spring5.x
、SpringBoot2.x
技術(shù)版本進(jìn)行編寫嘿辟,意在提供簡單方便舆瘪、可擴(kuò)展的統(tǒng)一API路由管理方式片效。
概念解釋:
-
Route(路由)
:路由是網(wǎng)關(guān)的基本單元,由ID英古、URI淀衣、一組Predicate、一組Filter組成召调,根據(jù)Predicate進(jìn)行匹配轉(zhuǎn)發(fā)膨桥。 -
Predicate(謂語、斷言)
:路由轉(zhuǎn)發(fā)的判斷條件唠叛,目前SpringCloud Gateway
支持多種方式只嚣,常見如:Path
、Query
艺沼、Method
册舞、Header
等。 -
Filter(過濾器)
:過濾器是路由轉(zhuǎn)發(fā)請求時所經(jīng)過的過濾邏輯澳厢,可用于修改請求环础、響應(yīng)內(nèi)容。
Spring Cloud GateWay 工作流程如下所示:
客戶端向Spring Cloud Gateway
發(fā)出請求剩拢。如果網(wǎng)關(guān)處理程序映射確定請求與路由匹配线得,則將其發(fā)送到網(wǎng)關(guān)Web處理程序。此處理程序運行時通過特定于請求的篩選鏈發(fā)送請求徐伐。過濾器被虛線分隔的原因是過濾器可以在發(fā)送代理請求之前或之后執(zhí)行邏輯贯钩。執(zhí)行所有“預(yù)”過濾邏輯,然后發(fā)出代理請求办素。在發(fā)出代理請求后角雷,將執(zhí)行“post”過濾器邏輯。
開始使用
Spring Cloud Gateway
目前有兩種方式進(jìn)行配置:
-
application.yml
配置文件方式 - 通過@Bean注解
RouteLocator
方法返回值
在本章會側(cè)重針對配置文件方式進(jìn)行講解性穿,當(dāng)然RouteLocator
方式也會簡單的告訴大家的使用方式勺三。
添加依賴
添加Spring Cloud Gateway
相關(guān)依賴,pom.xml
如下所示:
//...省略部分內(nèi)容
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<!--Spring Cloud Gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
//...省略部分內(nèi)容
Spring Cloud Gateway Predicates
在我們開始本章內(nèi)容之前我們要來先了解下Spring Cloud Gateway
內(nèi)部提供的所有謂語需曾、斷言
吗坚,這樣我們才能目標(biāo)性的進(jìn)行學(xué)習(xí),我整理出來了一個腦圖呆万,如下所示:
每一個Predicate
的使用商源,你可以理解為:當(dāng)滿足這種條件后才會被轉(zhuǎn)發(fā)
,如果是多個谋减,那就是都滿足的情況下被轉(zhuǎn)發(fā)牡彻。
Path 方式匹配轉(zhuǎn)發(fā)
通過Path
轉(zhuǎn)發(fā)示例,我們講解下上面的兩種配置出爹,分別是application.yml
以及RouteLocator
庄吼。
配置文件匹配地址轉(zhuǎn)發(fā)
我們在application.yml
配置文件內(nèi)添加對應(yīng)的路由配置缎除,如下所示:
spring:
application:
name: spring-cloud-gateway-sample
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
# 匹配路徑轉(zhuǎn)發(fā)
- Path=/api-boot-datasource-switch.html
# 端口號
server:
port: 9090
先來解釋下route
的組成部分:
-
id
:路由的ID -
uri
:匹配路由的轉(zhuǎn)發(fā)地址 -
predicates
:配置該路由的斷言,通過PredicateDefinition
類進(jìn)行接收配置总寻。
在上面的配置中伴找,當(dāng)訪問http://localhost:9090/api-boot-datasource-switch.html
時就會被自動轉(zhuǎn)發(fā)到http://blog.yuqiyu.com/api-boot-datasource-switch.html
,這里要注意完全匹配Path
的值時才會進(jìn)行路由轉(zhuǎn)發(fā)废菱。
訪問效果如下所示:
RouteLocator 匹配路徑轉(zhuǎn)發(fā)
在上面的配置中,如果使用RouteLocator
方式該怎么進(jìn)行配置呢抖誉?
如下所示:
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("blog", r ->
r.path("/api-boot-datasource-switch.html").uri("http://blog.yuqiyu.com"))
.build();
}
Before 方式匹配轉(zhuǎn)發(fā)
當(dāng)部署有訪問時間限制的接口時殊轴,我們可以通過Before Predicate
來完成某一個時間點之前允許訪問,過時后則不允許轉(zhuǎn)發(fā)請求到具體的服務(wù)袒炉,配置如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Before=2019-05-01T00:00:00+08:00[Asia/Shanghai]
在上面配置中旁理,我們允許2019-05-01
日凌晨之前通過路由轉(zhuǎn)發(fā)到http://blog.yuqiyu.com
,通過查看org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicateFactory
源碼我們發(fā)現(xiàn)我磁,Spring Cloud Gateway
的Before
斷言采用的ZonedDateTime
進(jìn)行匹配時間孽文,這里要注意存在時區(qū)的問題,需要配置[Asia/Shanghai]
作為中國時區(qū)夺艰。
After 方式匹配轉(zhuǎn)發(fā)
After Predicate
與Before
配置使用一致芋哭,匹配某一個時間點之后允許路由轉(zhuǎn)發(fā),如下所示配置:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- After=2019-04-29T00:00:00+08:00[Asia/Shanghai]
在上面配置中允許2019-04-29
凌晨之后進(jìn)行轉(zhuǎn)發(fā)到http://blog.yuqiyu.com
郁副。
Between 方式匹配轉(zhuǎn)發(fā)
那如果是一個時間段內(nèi)允許請求轉(zhuǎn)發(fā)减牺,通過Before
、After
組合配置也可以完成存谎,不過Spring Cloud Gateway
還是提供了Between
方式拔疚,如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Between=2019-04-29T00:00:00+08:00[Asia/Shanghai], 2019-05-01T00:00:00+08:00[Asia/Shanghai]
在上面配置中,允許在2019-04-29
日凌晨后 & 2019-05-01
凌晨之前請求轉(zhuǎn)發(fā)到http://blog.yuqiyu.com
既荚。
Cookie 方式匹配轉(zhuǎn)發(fā)
Spring Cloud Gateway
還提供了根據(jù)Cookie
值的方式匹配轉(zhuǎn)發(fā)請求稚失,如果請求中所攜帶的Cookie
值與配置的Predicate
匹配,那么就可以被允許轉(zhuǎn)發(fā)到指定地址恰聘,如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Cookie=hengboy, yuqiyu
在上面配置中句各,如果客戶端發(fā)送請求時攜帶了"hengboy=yuqiyu"
的Cookie信息,則允許請求轉(zhuǎn)發(fā)憨琳。
測試Cookie方式轉(zhuǎn)發(fā):
curl http://localhost:9090 --cookie "hengboy=yuqiyu"
通過上面方式我們是可以成功轉(zhuǎn)發(fā)請求的诫钓,如果我們修改Cookie
的值,就會導(dǎo)致無法轉(zhuǎn)發(fā)
篙螟,出現(xiàn)404菌湃。
Header 方式匹配轉(zhuǎn)發(fā)
Spring Cloud Gateway
可以根據(jù)發(fā)送請求的Header
信息進(jìn)行匹配轉(zhuǎn)發(fā),加入我們可以根據(jù)X-Request-Id
的值進(jìn)行匹配遍略,如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Header=X-Request-Id, \d+
在上面配置中惧所,如果X-Request-Id
的值為數(shù)字骤坐,那么就可以轉(zhuǎn)發(fā)到http://blog.yuqiyu.com
,我們通過如下方式進(jìn)行測試:
curl http://localhost:9090 -H "X-Request-Id:123456"
如果頭信息為X-Request-Id:abc
時下愈,就會轉(zhuǎn)發(fā)失敗纽绍,出現(xiàn)404。
Host 方式匹配轉(zhuǎn)發(fā)
Spring Cloud Gateway
可以根據(jù)Host
主機(jī)名進(jìn)行匹配轉(zhuǎn)發(fā)势似,如果我們的接口只允許**.yuqiyu.com
域名進(jìn)行訪問拌夏,那么配置如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Host=**.yuqiyu.com
測試如下所示:
1. curl http://localhost:9090 -H "Host: yuqiyu.com" // 匹配
2. curl http://localhost:9090 -H "Host: api.yuqiyu.com" // 匹配
3. curl http://localhost:9090 -H "Host: admin.yuqiyu.com" // 匹配
3. curl http://localhost:9090 -H "Host: hengboy.com" // 不匹配
請求方式 方式匹配轉(zhuǎn)發(fā)
Rest
請求風(fēng)格的接口內(nèi)往往會存在多種請求方式的接口,如果我們的接口只允許POST
請求訪問履因,那么配置如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Method=POST
發(fā)送GET
請求測試:
~ curl http://localhost:9090
{"timestamp":"2019-04-29T06:27:41.121+0000","path":"/","status":404,"error":"Not Found","message":null}
我們的請求并未被Spring Cloud Gateway
進(jìn)行轉(zhuǎn)發(fā)障簿,那么我們再來通過POST
請求進(jìn)行測試:
curl -X POST http://localhost:9090
是可以被轉(zhuǎn)發(fā)到目標(biāo)地址uri
的,不過我的這個博客是OSS
部署的栅迄,阿里云限制了POST
訪問站故,盡管如此我們也證明了可以轉(zhuǎn)發(fā)。
請求參數(shù) 方式匹配轉(zhuǎn)發(fā)
Spring Cloud GateWay
還支持根據(jù)指定的參數(shù)進(jìn)行匹配毅舆,Query
方式的Predicate
也有兩種方式匹配情況西篓,如下所示:
-
請求中存在
xxx
參數(shù)spring: cloud: gateway: routes: - id: blog uri: http://blog.yuqiyu.com predicates: - Query=xxx
我們通過
curl http://localhost:9090\?xxx\=123
是可以被成功轉(zhuǎn)發(fā)的,只要參數(shù)存在xxx
就會被成功轉(zhuǎn)發(fā)憋活,否則出現(xiàn)404轉(zhuǎn)發(fā)失敗岂津。 -
請求中存在
xxx
參數(shù)且值為zzz
spring: cloud: gateway: routes: - id: blog uri: http://blog.yuqiyu.com predicates: - Query=xxx, zzz
根據(jù)上面配置,我們限定了參數(shù)
xxx
必須為zzz
時才會被成功轉(zhuǎn)發(fā)余掖,否則同樣會出現(xiàn)404抓發(fā)失敗寸爆。
請求路徑 方式匹配轉(zhuǎn)發(fā)
Spring Cloud Gateway
提供了請求路徑變量方式匹配轉(zhuǎn)發(fā),如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Path=/article/{articleId}
在上面配置中{articleId}
是一個路徑變量盐欺,可以是任意值赁豆,匹配/article/1
、/article/abc
等冗美,測試如下所示:
~ curl http://localhost:9090/article/1 // 匹配
~ curl http://localhost:9090/article/abc // 匹配
~ curl http://localhost:9090/article/1/1 // 不匹配
請求IP 方式匹配轉(zhuǎn)發(fā)
Spring Cloud Gateway
可以限制允許訪問接口的客戶端IP
地址魔种,配置后只對指定IP
地址的客戶端進(jìn)行請求轉(zhuǎn)發(fā),配置如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- RemoteAddr=192.168.1.56/24
在上面我們配置了192.168.1.56/24
粉洼,其中192.168.1.56
是客戶端的IP
地址节预,而24
則是子網(wǎng)掩碼。
組合示例
相同的Predicate
也可以配置多個属韧,請求的轉(zhuǎn)發(fā)是必須滿足所有的Predicate
后才可以進(jìn)行路由轉(zhuǎn)發(fā)安拟,組合使用示例如下所示:
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://blog.yuqiyu.com
predicates:
- Query=author, hengboy
- Query=yuqiyu
- Method=GET
- Cookie=hengboy, yuqiyu
- Header=X-Request-Id, \d+
- RemoteAddr=192.168.1.56/24
總結(jié)
本章節(jié)講解了Spring Cloud Gateway
的相關(guān)謂詞、斷言
基本使用方式宵喂,GateWay
內(nèi)部提供了很多種靈活的路由轉(zhuǎn)發(fā)規(guī)則糠赦,在同一個路由內(nèi)存在多個Predicate
時,同時滿足規(guī)則后請求才會被路由轉(zhuǎn)發(fā)。
源碼位置
Gitee
:https://gitee.com/hengboy/spring-cloud-chapter/tree/master/SpringCloud/spring-cloud-gateway