1 SpringCloud Gateway 簡介
SpringCloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基於 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在為微服務架構提供一種簡單有效的統一的 API 路由管理方式。
SpringCloud Gateway 作為 Spring Cloud 生態系統中的網關,目標是替代 Zuul,在Spring Cloud 2.0以上版本中,沒有對新版本的Zuul 2.0以上最新高性能版本進行集成,仍然還是使用的Zuul 2.0之前的非Reactor模式的老版本。而為了提升網關的性能,SpringCloud Gateway是基於WebFlux框架實現的,而WebFlux框架底層則使用了高性能的Reactor模式通信框架Netty。
Spring Cloud Gateway 的目標,不僅提供統一的路由方式,並且基於 Filter 鏈的方式提供了網關基本的功能,例如:安全,監控/指標,和限流。
提前聲明:Spring Cloud Gateway 底層使用了高性能的通信框架Netty。
引入依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 需要注冊到eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2 Spring Cloud Gateway路由配置方式
yaml文件配置
server: port: 8080 spring: application: name: api-gateway cloud: gateway: routes: -id: url-proxy-1 uri: https://blog.csdn.net predicates: -Path=/csdn
各字段含義如下:
id:我們自定義的路由 ID,保持唯一
uri:目標服務地址
predicates:路由條件,Predicate 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默認方法來將 Predicate 組合成其他復雜的邏輯(比如:與,或,非)。
上面這段配置的意思是,配置了一個 id 為 url-proxy-1的URI代理規則,
路由的規則為:
當訪問地址http://localhost:8080/csdn/1.jsp時,會路由到上游地址https://blog.csdn.net/1.jsp。
基於代碼的路由配置方式
轉發功能同樣可以通過代碼來實現,我們可以在啟動類 GateWayApplication 中添加方法 customRouteLocator() 來定制轉發規則。
package com.springcloud.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; @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(); } }
3.Predicate的配置使用
Predicate 就是為了實現一組匹配規則,方便讓請求過來找到對應的 Route 進行處理
1.通過請求參數匹配
Query Route Predicate 支持傳入兩個參數,一個是屬性名一個為屬性值,屬性值可以是正則表達式。
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 屬性的參數即可匹配路由。
使用 curl 測試,命令行輸入:
curl localhost:8080?smile=x&id=2
經過測試發現只要請求匯總帶有 smile 參數即會匹配路由,不帶 smile 參數則不會匹配。
還可以將 Query 的值以鍵值對的方式進行配置,這樣在請求過來時會對屬性值和正則進行匹配,匹配上才會走路由
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.
這樣只要當請求中包含 keep 屬性並且參數值是以 pu 開頭的長度為三位的字符串才會進行匹配和路由。
使用 curl 測試,命令行輸入:
curl localhost:8080?keep=pub
測試可以返回頁面代碼,將 keep 的屬性值改為 pubx 再次訪問就會報 404,證明路由需要匹配正則表達式才會進行路由。
2.通過 Header 屬性匹配
Header Route Predicate 和 Cookie Route Predicate 一樣,也是接收 2 個參數,一個 header 中屬性名稱和一個正則表達式,這個屬性值和正則表達式匹配則執行。
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"
則返回頁面代碼證明匹配成功。將參數-H "X-Request-Id:88"改為-H "X-Request-Id:spring"再次執行時返回404證明沒有匹配。
3.通過 Cookie 匹配
Cookie Route Predicate 可以接收兩個參數,一個是 Cookie name ,一個是正則表達式,路由規則會通過獲取對應的 Cookie name 值和正則表達式去匹配,如果匹配上就會執行路由,如果沒有匹配上則不執行。
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"
則會返回頁面代碼,如果去掉--cookie "sessionId=test",后台匯報 404 錯誤。
4.通過 Host 匹配
Host Route Predicate 接收一組參數,一組匹配的域名列表,這個模板是一個 ant 分隔的模板,用.號作為分隔符。它通過參數中的主機地址作為匹配規則。
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"
經測試以上兩種 host 均可匹配到 host_route 路由,去掉 host 參數則會報 404 錯誤。
6 通過請求方式匹配
可以通過是 POST、GET、PUT、DELETE 等不同的請求方式來進行路由。
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 默認是以 GET 的方式去請求
測試返回頁面代碼,證明匹配到路由,我們再以 POST 的方式請求測試。
# curl 默認是以 GET 的方式去請求
curl -X POST http://localhost:8080
返回 404 沒有找到,證明沒有匹配上路由
7 通過請求路徑匹配
Path Route Predicate 接收一個匹配路徑的參數來判斷是否走路由。
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
經過測試第一和第二條命令可以正常獲取到頁面返回值,最后一個命令報404,證明路由是通過指定路由來匹配。
8 通過請求 ip 地址進行匹配
Predicate 也支持通過設置某個 ip 區間號段的請求才會路由,RemoteAddr Route Predicate 接受 cidr 符號(IPv4 或 IPv6 )字符串的列表(最小大小為1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子網掩碼)。
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
可以將此地址設置為本機的 ip 地址進行測試。
curl localhost:8080
如果請求的遠程地址是 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的官方參考:
# 匹配在什么時間之后的 - After=2017-01-20T17:42:47.789-07:00[America/Denver] # 匹配在什么時間之前的 - Before=2017-01-20T17:42:47.789-07:00[America/Denver] # 匹配在某段時間的 - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] # 匹配cookie名稱為`chocolate`的值要符合`ch.p`正則. - Cookie=chocolate, ch.p # 匹配header為`X-Request-Id`的值要符合`\d+`正則. - Header=X-Request-Id, \d+ # 匹配任意符合`**.somehost.org`與`**.anotherhost.org`正則的網址 - Host=**.somehost.org,**.anotherhost.org # Host還支持模版變量,會保存在`ServerWebExchange.getAttributes()`的 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中,以Map形式存儲 - Host={sub}.myhost.org # 匹配GET方法 - Method=GET # 路徑匹配,與Host一樣支持模版變量,存在URI_TEMPLATE_VARIABLES_ATTRIBUTE中。 - Path=/foo/{segment},/bar/{segment} # 匹配存在baz查詢參數 - Query=baz # 匹配存在foo且符合`ba.`正則 - Query=foo, ba. # 匹配遠程地址 - RemoteAddr=192.168.1.1/24
4.和注冊中心相結合的路由配置方式
在uri的schema協議部分為自定義的lb:類型,表示從微服務注冊中心(如Eureka)訂閱服務,並且進行服務的路由。
一個典型的示例如下:
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/
注冊中心相結合的路由配置方式,與單個URI的路由配置,區別其實很小,僅僅在於URI的schema協議不同。單個URI的地址的schema協議,一般為http或者https協議。
5.高級功能-實現熔斷降級
為什么要實現熔斷降級?
在分布式系統中,網關作為流量的入口,因此會有大量的請求進入網關,向其他服務發起調用,其他服務不可避免的會出現調用失敗(超時、異常),失敗時不能讓請求堆積在網關上,需要快速失敗並返回給客戶端,想要實現這個要求,就必須在網關上做熔斷、降級操作。
server.port: 8082 spring: application: name: gateway redis: host: localhost port: 6379 password: 123456 cloud: gateway: routes: - id: rateLimit_route uri: http://localhost:8000 order: 0 predicates: - Path=/test/** filters: - StripPrefix=1 - name: Hystrix args: name: fallbackCmdA fallbackUri: forward:/fallbackA hystrix.command.fallbackCmdA.execution.isolation.thread.timeoutInMilliseconds: 5000
這里的配置,使用了兩個過濾器:
(1)過濾器StripPrefix,作用是去掉請求路徑的最前面n個部分截取掉。
StripPrefix=1就代表截取路徑的個數為1,比如前端過來請求/test/good/1/view,匹配成功后,路由到后端的請求路徑就會變成http://localhost:8888/good/1/view。
(2)過濾器Hystrix,作用是通過Hystrix進行熔斷降級
當上游的請求,進入了Hystrix熔斷降級機制時,就會調用fallbackUri配置的降級地址。需要注意的是,還需要單獨設置Hystrix的commandKey的超時時間
fallbackUri配置的降級地址的代碼如下:

package org.gateway.controller; import org.gateway.response.Response; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class FallbackController { @GetMapping("/fallbackA") public Response fallbackA() { Response response = new Response(); response.setCode("100"); response.setMessage("服務暫時不可用"); return response; } }
6.高級功能-分布式限流
這邊就不拓展了
轉載自:https://www.cnblogs.com/crazymakercircle/p/11704077.html