Spring Cloud GateWay
Spring 自己開發(fā)的新一代API網(wǎng)關(guān)產(chǎn)品,基于NIO異步處理,摒棄了Zuul基于Servlet同步通信的設(shè)計(jì)。
Spring Cloud Gateway 作為 Spring Cloud 生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標(biāo)是替代 Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全,監(jiān)控/指標(biāo),和限流。
關(guān)鍵特征:
- 1、基于JDK8+開發(fā)。
- 2、Spring Cloud Gateway 是 Spring Cloud 的一個(gè)全新項(xiàng)目,該項(xiàng)目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡單有效的統(tǒng)一的 API 路由管理方式。
- 3、支持動(dòng)態(tài)路由,能夠匹配任何請求屬性上的路由。
- 4、支持基于HTTP請求的路由匹配(Path、Method、Header、Host等)。
- 5、過濾器可以修改HTTP請求和HTTP響應(yīng)。
在性能方面,根據(jù)官方提供的基準(zhǔn)測試, Spring Cloud Gateway 的 RPS(每秒請求數(shù))是Zuul 的 1.6 倍。
Spring Cloud Gateway十分優(yōu)秀,Spring Cloud Alibaba也默認(rèn)選用該組件作為網(wǎng)關(guān)產(chǎn)品。
相關(guān)概念:
- Route(路由):這是網(wǎng)關(guān)的基本構(gòu)建塊。它由一個(gè) ID,一個(gè)目標(biāo) URI,一組斷言和一組過濾器定義。如果斷言為真,則路由匹配。
- Predicate(斷言):這是一個(gè) Java 8 的 Predicate。輸入類型是一個(gè) ServerWebExchange。我們可以使用它來匹配來自 HTTP 請求的任何內(nèi)容,例如 headers 或參數(shù)。
- Filter(過濾器):這是org.springframework.cloud.gateway.filter.GatewayFilter的實(shí)例,我們可以使用它修改請求和響應(yīng)。
工作流程:

客戶端向 Spring Cloud Gateway 發(fā)出請求。如果 Gateway Handler Mapping 中找到與請求相匹配的路由,將其發(fā)送到 Gateway Web Handler。Handler 再通過指定的過濾器鏈來將請求發(fā)送到我們實(shí)際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。 過濾器之間用虛線分開是因?yàn)檫^濾器可能會(huì)在發(fā)送代理請求之前(“pre”)或之后(“post”)執(zhí)行業(yè)務(wù)邏輯。
Spring Cloud Gateway 的特征:
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
- 動(dòng)態(tài)路由
- Predicates 和 Filters 作用于特定路由
- 集成 Hystrix 斷路器
- 集成 Spring Cloud DiscoveryClient
- 易于編寫的 Predicates 和 Filters
- 限流
- 路徑重寫
Spring Cloud GateWay 快速上手
Spring Cloud Gateway 網(wǎng)關(guān)路由有兩種配置方式:
- 在配置文件 yml 中配置
- 通過@Bean自定義 RouteLocator,在啟動(dòng)主類 Application 中配置
這兩種方式是等價(jià)的,建議使用 yml 方式進(jìn)配置。
引入依賴:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--整合Spring Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--整合Spring Cloud Alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Spring Cloud Gateway 是使用 netty+webflux 實(shí)現(xiàn)因此不需要再引入 web 模塊。
gateWay的主要功能之一是轉(zhuǎn)發(fā)請求,轉(zhuǎn)發(fā)規(guī)則的定義主要包含三個(gè)部分:
- 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等,寫法必須遵循 key=vlue的形式。
- Filter(過濾器):過濾器是路由轉(zhuǎn)發(fā)請求時(shí)所經(jīng)過的過濾邏輯,可用于修改請求、響應(yīng)內(nèi)容。
注意:其中Route和Predicate必須同時(shí)申明
路由配置方式
基礎(chǔ)URI路由配置方式
- 如果請求的目標(biāo)地址,是單個(gè)的URI資源路徑,配置文件示例如下:
//通過配置文件配置
spring:
cloud:
gateway:
routes:
- id: gate_route
uri: http://localhost:9023
predicates:
## 當(dāng)請求的路徑為gate、rule開頭的時(shí),轉(zhuǎn)發(fā)到http://localhost:9023服務(wù)器上
- Path=/gate/**,/rule/**
### 請求路徑前加上/app
filters:
- PrefixPath=/app
基于代碼的路由配置方式
轉(zhuǎn)發(fā)功能同樣可以通過代碼來實(shí)現(xiàn),我們可以在啟動(dòng)類 GateWayApplication 中添加方法 customRouteLocator() 來定制轉(zhuǎn)發(fā)規(guī)則。
@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("/csdn")
.uri("https://blog.csdn.net"))
.build();
}
}
上面配置了一個(gè) id 為 path_route 的路由,當(dāng)訪問地址http://localhost:8080/about時(shí)會(huì)自動(dòng)轉(zhuǎn)發(fā)到地址:https://blog.csdn.net/csdn和上面的轉(zhuǎn)發(fā)效果一樣,只是這里轉(zhuǎn)發(fā)的是以項(xiàng)目地址/csdn格式的請求地址。
和注冊中心相結(jié)合的路由配置方式
在uri的schema協(xié)議部分為自定義的lb:類型,表示從微服務(wù)注冊中心(如Eureka)訂閱服務(wù),并且進(jìn)行服務(wù)的路由。
server:
port: 8084
spring:
cloud:
gateway:
routes:
-id: seckill-provider-route
uri: lb://seckill-provider
predicates:
- Path=/seckill-provider/**
-id: message-provider-route
uri: lb://message-provider
predicates:
-Path=/message-provider/**
application:
name: cloud-gateway
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:8888/eureka/
注冊中心相結(jié)合的路由配置方式,與單個(gè)URI的路由配置,區(qū)別其實(shí)很小,僅僅在于URI的schema協(xié)議不同。單個(gè)URI的地址的schema協(xié)議,一般為http或者h(yuǎn)ttps協(xié)議。
路由匹配規(guī)則
Spring Cloud Gateway 的功能很強(qiáng)大,我們僅僅通過 Predicates 的設(shè)計(jì)就可以看出來,前面我們只是使用了 predicates 進(jìn)行了簡單的條件匹配,其實(shí) Spring Cloud Gataway 幫我們內(nèi)置了很多 Predicates 功能。
Spring Cloud Gateway 是通過 Spring WebFlux 的 HandlerMapping 做為底層支持來匹配到轉(zhuǎn)發(fā)路由,Spring Cloud Gateway 內(nèi)置了很多 Predicates 工廠,這些 Predicates 工廠通過不同的 HTTP 請求參數(shù)來匹配,多個(gè) Predicates 工廠可以組合使用。

Predicate 斷言條件(轉(zhuǎn)發(fā)規(guī)則)介紹
Predicate 來源于 Java 8,是 Java 8 中引入的一個(gè)函數(shù),Predicate 接受一個(gè)輸入?yún)?shù),返回一個(gè)布爾值結(jié)果。該接口包含多種默認(rèn)方法來將 Predicate 組合成其他復(fù)雜的邏輯(比如:與,或,非)。可以用于接口請求參數(shù)校驗(yàn)、判斷新老數(shù)據(jù)是否有變化需要進(jìn)行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性實(shí)現(xiàn)了各種路由匹配規(guī)則,有通過 Header、請求參數(shù)等不同的條件來進(jìn)行作為條件匹配到對應(yīng)的路由。網(wǎng)上有一張圖總結(jié)了 Spring Cloud 內(nèi)置的幾種 Predicate 的實(shí)現(xiàn)。

說白了 Predicate 就是為了實(shí)現(xiàn)一組匹配規(guī)則,方便讓請求過來找到對應(yīng)的 Route 進(jìn)行處理,接下來我們接下 Spring Cloud GateWay 內(nèi)置幾種 Predicate 的使用。
- 轉(zhuǎn)發(fā)規(guī)則(predicates),假設(shè) 轉(zhuǎn)發(fā)uri都設(shè)定為http://localhost:9023
| 規(guī)則 | 實(shí)例 | 說明 |
|---|---|---|
| Path | - Path=/gate/,/rule/ | 當(dāng)請求的路徑為gate、rule開頭的時(shí),轉(zhuǎn)發(fā)到http://localhost:9023服務(wù)器上 |
| Before | - Before=2017-01-20T17:42:47.789-07:00[America/Denver] | 在某個(gè)時(shí)間之前的請求才會(huì)被轉(zhuǎn)發(fā)到 http://localhost:9023服務(wù)器上 |
| After | - After=2017-01-20T17:42:47.789-07:00[America/Denver] | 在某個(gè)時(shí)間之后的請求才會(huì)被轉(zhuǎn)發(fā) |
| Between | - Between=2017-01-20T17:42:47.789-07:00[America/Denver],2017-01-21T17:42:47.789-07:00[America/Denver] | 在某個(gè)時(shí)間段之間的才會(huì)被轉(zhuǎn)發(fā) |
| Cookie | - Cookie=chocolate, ch.p | 名為chocolate的表單或者滿足正則ch.p的表單才會(huì)被匹配到進(jìn)行請求轉(zhuǎn)發(fā) |
| Header | - Header=X-Request-Id, \d+ | 攜帶參數(shù)X-Request-Id或者滿足\d+的請求頭才會(huì)匹配 |
| Host | - Host=www.hd123.com | 當(dāng)主機(jī)名為www.hd123.com的時(shí)候直接轉(zhuǎn)發(fā)到http://localhost:9023服務(wù)器上 |
| Method | - Method=GET | 只有GET方法才會(huì)匹配轉(zhuǎn)發(fā)請求,還可以限定POST、PUT等請求方式 |

通過請求參數(shù)匹配
- Query Route Predicate 支持傳入兩個(gè)參數(shù),一個(gè)是屬性名一個(gè)為屬性值,屬性值可以是正則表達(dá)式。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Query=smile
只要請求中包含 smile 屬性的參數(shù)即可匹配路由,不帶 smile 參數(shù)則不會(huì)匹配。
curl localhost:8080?smile=x&id=2
- 還可以將 Query 的值以鍵值對的方式進(jìn)行配置,這樣在請求過來時(shí)會(huì)對屬性值和正則進(jìn)行匹配,匹配上才會(huì)走路由。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Query=keep, pu.
這樣只要當(dāng)請求中包含 keep 屬性并且參數(shù)值是以 pu 開頭的長度為三位的字符串才會(huì)進(jìn)行匹配和路由。
curl localhost:8080?keep=pub
通過 Header 屬性匹配
Header Route Predicate 和 Cookie Route Predicate 一樣,也是接收 2 個(gè)參數(shù),一個(gè) header 中屬性名稱和一個(gè)正則表達(dá)式,這個(gè)屬性值和正則表達(dá)式匹配則執(zhí)行。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Header=X-Request-Id, \d+
使用 curl 測試,命令行輸入:
curl http://localhost:8080 -H "X-Request-Id:88"
則返回頁面代碼證明匹配成功。將參數(shù)-H "X-Request-Id:88"改為-H "X-Request-Id:spring"再次執(zhí)行時(shí)返回404證明沒有匹配。
通過 Cookie 匹配
Cookie Route Predicate 可以接收兩個(gè)參數(shù),一個(gè)是 Cookie name ,一個(gè)是正則表達(dá)式,路由規(guī)則會(huì)通過獲取對應(yīng)的 Cookie name 值和正則表達(dá)式去匹配,如果匹配上就會(huì)執(zhí)行路由,如果沒有匹配上則不執(zhí)行。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Cookie=sessionId, test
使用 curl 測試,命令行輸入:
curl http://localhost:8080 --cookie "sessionId=test"
則會(huì)返回頁面代碼,如果去掉--cookie "sessionId=test",后臺(tái)匯報(bào) 404 錯(cuò)誤。
通過 Host 匹配
Host Route Predicate 接收一組參數(shù),一組匹配的域名列表,這個(gè)模板是一個(gè) ant 分隔的模板,用.號作為分隔符。它通過參數(shù)中的主機(jī)地址作為匹配規(guī)則。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Host=**.baidu.com
使用 curl 測試,命令行輸入:
curl http://localhost:8080 -H "Host: www.baidu.com"
curl http://localhost:8080 -H "Host: md.baidu.com"
經(jīng)測試以上兩種 host 均可匹配到 host_route 路由,去掉 host 參數(shù)則會(huì)報(bào) 404 錯(cuò)誤。
通過請求方式匹配
可以通過是 POST、GET、PUT、DELETE 等不同的請求方式來進(jìn)行路由。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Method=GET
使用 curl 測試,命令行輸入:
# curl 默認(rèn)是以 GET 的方式去請求
curl http://localhost:8080
測試返回頁面代碼,證明匹配到路由,我們再以 POST 的方式請求測試。
# curl 默認(rèn)是以 GET 的方式去請求
curl -X POST http://localhost:8080
返回 404 沒有找到,證明沒有匹配上路由。
通過請求路徑匹配
Path Route Predicate 接收一個(gè)匹配路徑的參數(shù)來判斷是否走路由。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: http://ityouknow.com
order: 0
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
經(jīng)過測試第一和第二條命令可以正常獲取到頁面返回值,最后一個(gè)命令報(bào)404,證明路由是通過指定路由來匹配。
通過請求 ip 地址進(jìn)行匹配
Predicate 也支持通過設(shè)置某個(gè) ip 區(qū)間號段的請求才會(huì)路由,RemoteAddr Route Predicate 接受 cidr 符號(IPv4 或 IPv6 )字符串的列表(最小大小為1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子網(wǎng)掩碼)。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- RemoteAddr=192.168.1.1/24
可以將此地址設(shè)置為本機(jī)的 ip 地址進(jìn)行測試。
curl localhost:8080
如果請求的遠(yuǎn)程地址是 192.168.1.10,則此路由將匹配。
組合使用
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Host=**.foo.org
- Path=/headers
- Method=GET
- Header=X-Request-Id, \d+
- Query=foo, ba.
- Query=baz
- Cookie=chocolate, ch.p
各種 Predicates 同時(shí)存在于同一個(gè)路由時(shí),請求必須同時(shí)滿足所有的條件才被這個(gè)路由匹配。
一個(gè)請求滿足多個(gè)路由的斷言條件時(shí),請求只會(huì)被首個(gè)成功匹配的路由轉(zhuǎn)發(fā)。
過濾器規(guī)則(Filter)
| 過濾規(guī)則 | 實(shí)例 | 說明 |
|---|---|---|
| PrefixPath | - PrefixPath=/app | 在請求路徑前加上app |
| RewritePath | - RewritePath=/test, /app/test | 訪問localhost:9022/test,請求會(huì)轉(zhuǎn)發(fā)到localhost:8001/app/test |
| SetPath | SetPath=/app/{path} | 通過模板設(shè)置路徑,轉(zhuǎn)發(fā)的規(guī)則時(shí)會(huì)在路徑前增加app,{path}表示原請求路徑 |
| RedirectTo | 重定向 | |
| RemoveRequestHeader | 去掉某個(gè)請求頭信息 |
注意:當(dāng)配置多個(gè)filter時(shí),優(yōu)先定義的會(huì)被調(diào)用,剩余的filter將不會(huì)生效
PrefixPath
- 對所有的請求路徑添加前綴:
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
訪問/hello的請求被發(fā)送到https://example.org/mypath/hello。
RedirectTo
- 重定向,配置包含重定向的返回碼和地址:
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
RemoveRequestHeader
- 去掉某個(gè)請求頭信息:
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
去掉請求頭信息 X-Request-Foo
RemoveResponseHeader
- 去掉某個(gè)回執(zhí)頭信息:
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Request-Foo
RemoveRequestParameter
- 去掉某個(gè)請求參數(shù)信息:
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red
RewritePath
- 改寫路徑:
spring:
cloud:
gateway:
routes:
- id: rewrite_filter
uri: http://localhost:8081
predicates:
- Path=/test/**
filters:
- RewritePath=/where(?<segment>/?.*), /test(?<segment>/?.*)
/where/... 改成 test/...
使用代碼改下路徑
RouteLocatorBuilder.Builder builder = routeLocatorBuilder.routes();
builder.route("path_rote_at_guigu", r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei"))
.route("csdn_route", r -> r.path("/csdn")
.uri("https://blog.csdn.net"))
.route("blog3_rewrite_filter", r -> r.path("/blog3/**")
.filters(f -> f.rewritePath("/blog3/(?<segment>.*)", "/$\\{segment}"))
.uri("https://blog.csdn.net"))
.route("rewritepath_route", r -> r.path("/baidu/**")
.filters(f -> f.rewritePath("/baidu/(?<segment>.*)", "/$\\{segment}"))
.uri("http://www.baidu.com"))
.build();
SetPath
- 設(shè)置請求路徑,與RewritePath類似。
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- SetPath=/{segment}
如/red/blue的請求被轉(zhuǎn)發(fā)到/blue。
SetRequestHeader
- 設(shè)置請求頭信息。
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
filters:
- SetRequestHeader=X-Request-Red, Blue
SetStatus
- 設(shè)置回執(zhí)狀態(tài)碼。
spring:
cloud:
gateway:
routes:
- id: setstatusint_route
uri: https://example.org
filters:
- SetStatus=401
StripPrefix
- 跳過指定路徑。
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
請求/name/blue/red會(huì)轉(zhuǎn)發(fā)到/red。
RequestSize
- 請求大小。
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http://localhost:8080/upload
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
maxSize: 5000000
超過5M的請求會(huì)返回413錯(cuò)誤。
Default-filters
- 對所有請求添加過濾器。
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
通過代碼進(jìn)行配置
- 通過代碼進(jìn)行配置,將路由規(guī)則設(shè)置為一個(gè)Bean即可:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.route("host_route", r -> r.host("*.myhost.org")
.uri("http://httpbin.org"))
.route("rewrite_route", r -> r.host("*.rewrite.org")
.filters(f -> f.rewritePath("/foo/(?<segment>.*)", "/${segment}"))
.uri("http://httpbin.org"))
.route("hystrix_route", r -> r.host("*.hystrix.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
.uri("http://httpbin.org"))
.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
.uri("http://httpbin.org"))
.route("limit_route", r -> r
.host("*.limited.org").and().path("/anything/**")
.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
.uri("http://httpbin.org"))
.build();
}
統(tǒng)一配置跨域請求:
現(xiàn)在的請求通過經(jīng)過gateWay網(wǎng)關(guān)時(shí),需要在網(wǎng)關(guān)統(tǒng)一配置跨域請求,需求所有請求通過
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-headers: "*"
allow-credentials: true
allowed-methods:
- GET
- POST
- DELETE
- PUT
- OPTION
Gatway 網(wǎng)關(guān)的過濾器開發(fā)
過濾器的執(zhí)行次序
Spring-Cloud-Gateway 基于過濾器實(shí)現(xiàn),同 zuul 類似,有pre和post兩種方式的 filter,分別處理前置邏輯和后置邏輯??蛻舳说恼埱笙冉?jīng)過pre類型的 filter,然后將請求轉(zhuǎn)發(fā)到具體的業(yè)務(wù)服務(wù),收到業(yè)務(wù)服務(wù)的響應(yīng)之后,再經(jīng)過post類型的 filter 處理,最后返回響應(yīng)到客戶端。
過濾器執(zhí)行流程如下,order 越大,優(yōu)先級越低

Spring Cloud Gateway根據(jù)作用范圍劃分為GatewayFilter和GlobalFilter,二者區(qū)別如下:
GatewayFilter:需要通過spring.cloud.routes.filters 配置在具體路由下,只作用在當(dāng)前路由上或通過spring.cloud.default-filters配置在全局,作用在所有路由上
GlobalFilter:全局過濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過GatewayFilterAdapter包裝成GatewayFilterChain可識(shí)別的過濾器,它為請求業(yè)務(wù)以及路由的URI轉(zhuǎn)換為真實(shí)業(yè)務(wù)服務(wù)的請求地址的核心過濾器,不需要配置,系統(tǒng)初始化時(shí)加載,并作用在每個(gè)路由上。
Spring Cloud Gateway框架內(nèi)置的GlobalFilter如下:

定義全局過濾器
實(shí)現(xiàn) GlobalFilter 和 Ordered,重寫相關(guān)方法,加入到spring容器管理即可,無需配置,全局過濾器對所有的路由都有效。
全局過濾器舉例:代碼如下:
@Configuration
public class FilterConfig {
@Bean
@Order(-1)
public GlobalFilter a() {
return new AFilter();
}
@Bean
@Order(0)
public GlobalFilter b() {
return new BFilter();
}
@Bean
@Order(1)
public GlobalFilter c() {
return new CFilter();
}
@Slf4j
public class AFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("AFilter前置邏輯");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("AFilter后置邏輯");
}));
}
//值越小,優(yōu)先級越高
//int HIGHEST_PRECEDENCE = -2147483648;
//int LOWEST_PRECEDENCE = 2147483647;
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 100;
}
}
@Slf4j
public class BFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("BFilter前置邏輯");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("BFilter后置邏輯");
}));
}
//值越小,優(yōu)先級越高
//int HIGHEST_PRECEDENCE = -2147483648;
//int LOWEST_PRECEDENCE = 2147483647;
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 200;
}
}
@Slf4j
public class CFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("CFilter前置邏輯");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("CFilter后置邏輯");
}));
}
//值越小,優(yōu)先級越高
//int HIGHEST_PRECEDENCE = -2147483648;
//int LOWEST_PRECEDENCE = 2147483647;
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 300;
}
}
}
定義局部過濾器
步驟:
- 1、需要實(shí)現(xiàn)GatewayFilter, Ordered,實(shí)現(xiàn)相關(guān)的方法
- 2、加入到過濾器工廠,并且注冊到spring容器中。
- 3、在配置文件中進(jìn)行配置,如果不配置則不啟用此過濾器規(guī)則。
局部過濾器舉例, 對請求頭部的 user-id 進(jìn)行校驗(yàn),代碼如下:
- 1、需要實(shí)現(xiàn)GatewayFilter, Ordered,實(shí)現(xiàn)相關(guān)的方法
@Slf4j
public class UserIdCheckGateWayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String url = exchange.getRequest().getPath().pathWithinApplication().value();
log.info("請求URL:" + url);
log.info("method:" + exchange.getRequest().getMethod());
//獲取param 請求參數(shù)
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
//獲取header
String userId = exchange.getRequest().getHeaders().getFirst("user-id");
log.info("userId:" + userId);
if (StringUtils.isEmpty(userId)) {
log.info("*****頭部驗(yàn)證不通過,請?jiān)陬^部輸入 user-id");
//終止請求,直接回應(yīng)
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
// 值越小,優(yōu)先級越高
//int HIGHEST_PRECEDENCE = -2147483648;
//int LOWEST_PRECEDENCE = 2147483647;
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
- 2、加入到過濾器工廠,并且注冊到spring容器中。
@Component
public class UserIdCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {
return new UserIdCheckGateWayFilter();
}
}
- 3、在配置文件中進(jìn)行配置,如果不配置則不啟用此過濾器規(guī)則。
- id: service_provider_demo_route_filter
uri: lb://service-provider-demo
predicates:
- Path=/filter/**
filters:
- RewritePath=/filter/(?<segment>.*), /provider/$\{segment}
- UserIdCheck
參考:
http://www.ityouknow.com/springcloud/2018/12/12/spring-cloud-gateway-start.html
http://www.likecs.com/show-50293.html
https://zhuanlan.zhihu.com/p/299608850?utm_source=wechat_session
https://juejin.cn/post/6844903965352525838
https://blog.csdn.net/weixin_38361347/article/details/114108368
http://www.zyiz.net/tech/detail-98256.html