路由謂詞工廠
Spring Cloud Gateway 將路由匹配作為 Spring WebFlux HandlerMapping 基礎設施的一部分。Spring Cloud Gateway 包含許多內建的路由斷言工廠。所有這些斷言都匹配 HTTP 請求的不同屬性。您可以將多個路由斷言工廠與邏輯 and 語句結合使用。
After 路由斷言工廠
After 路由斷言工廠接受一個引數:一個 datetime(即 Java ZonedDateTime)。此斷言匹配在指定日期時間之後發生的請求。以下示例配置了一個 After 路由斷言
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
此路由匹配在 2017 年 1 月 20 日 17:42 山區時間(丹佛)之後發出的任何請求。
Before 路由斷言工廠
Before 路由斷言工廠接受一個引數:一個 datetime(即 Java ZonedDateTime)。此斷言匹配在指定 datetime 之前發生的請求。以下示例配置了一個 Before 路由斷言
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
此路由匹配在 2017 年 1 月 20 日 17:42 山區時間(丹佛)之前發出的任何請求。
Between 路由斷言工廠
Between 路由斷言工廠接受兩個引數:datetime1 和 datetime2,它們是 Java ZonedDateTime 物件。此斷言匹配在 datetime1 之後且在 datetime2 之前發生的請求。datetime2 引數必須在 datetime1 之後。以下示例配置了一個 Between 路由斷言
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
此路由匹配在 2017 年 1 月 20 日 17:42 山區時間(丹佛)之後和 2017 年 1 月 21 日 17:42 山區時間(丹佛)之前發出的任何請求。這對於維護視窗可能很有用。
Cookie 路由斷言工廠
Cookie 路由斷言工廠接受兩個引數:cookie name 和一個 regexp(即 Java 正則表示式)。此斷言匹配具有給定名稱且其值與正則表示式匹配的 cookie。以下示例配置了一個 Cookie 路由斷言工廠
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
此路由匹配具有名為 chocolate 的 cookie 且其值與 ch.p 正則表示式匹配的請求。
Header 路由斷言工廠
Header 路由斷言工廠接受兩個引數:header 和一個 regexp(即 Java 正則表示式)。此斷言匹配具有給定名稱且其值與正則表示式匹配的請求頭。以下示例配置了一個 Header 路由斷言
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
如果請求具有名為 X-Request-Id 的請求頭,且其值與 \d+ 正則表示式匹配(即,其值為一個或多個數字),則此路由匹配。
Host 路由斷言工廠
Host 路由斷言工廠接受一個引數:主機名 patterns 列表。模式是一個 Ant 風格的模式,以 . 作為分隔符。此斷言匹配與模式匹配的 Host 請求頭。以下示例配置了一個 Host 路由斷言
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
也支援 URI 模板變數(例如 {sub}.myhost.org)。
如果請求具有 Host 請求頭,且其值為 www.somehost.org 或 beta.somehost.org 或 www.anotherhost.org,則此路由匹配。
此斷言將 URI 模板變數(例如前面示例中定義的 sub)提取為名稱和值的對映,並將其放在 ServerWebExchange.getAttributes() 中,鍵由 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 定義。這些值隨後可用於 GatewayFilter 工廠
Method 路由斷言工廠
Method 路由斷言工廠接受一個 methods 引數,該引數是一個或多個 HTTP 方法引數,用於匹配。以下示例配置了一個 Method 路由斷言
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
如果請求方法為 GET 或 POST,則此路由匹配。
Path 路由斷言工廠
Path 路由斷言工廠接受兩個引數:一個 Spring PathMatcher patterns 列表和一個可選的 matchTrailingSlash 標誌(預設為 true)。以下示例配置了一個 Path 路由斷言
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
如果請求路徑為例如:/red/1 或 /red/1/ 或 /red/blue 或 /blue/green,則此路由匹配。
如果將 matchTrailingSlash 設定為 false,則請求路徑 /red/1/ 將不匹配。
如果您設定了 spring.webflux.base-path 屬性,這將影響路徑匹配。屬性值將自動新增到路徑模式的前面。例如,如果 spring.webflux.base-path=/app 且路徑模式為 /red/{segment},則用於匹配的完整模式將是 /app/red/{segment}。
此斷言將 URI 模板變數(例如前面示例中定義的 segment)提取為名稱和值的對映,並將其放在 ServerWebExchange.getAttributes() 中,鍵由 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 定義。這些值隨後可用於 GatewayFilter 工廠
提供了一個實用方法(稱為 get)以方便訪問這些變數。以下示例展示瞭如何使用 get 方法
Map<String, String> uriVariables = ServerWebExchangeUtils.getUriTemplateVariables(exchange);
String segment = uriVariables.get("segment");
Query 路由斷言工廠
Query 路由斷言工廠接受兩個引數:一個必需的 param 和一個可選的 regexp(即 Java 正則表示式)。以下示例配置了一個 Query 路由斷言
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green
如果請求包含 green 查詢引數,則前面的路由匹配。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
如果請求包含 red 查詢引數,且其值匹配 gree. 正則表示式,則前面的路由匹配,因此 green 和 greet 將匹配。
RemoteAddr 路由斷言工廠
RemoteAddr 路由斷言工廠接受一個 sources 列表(最小長度為 1),這些源是 CIDR 表示法(IPv4 或 IPv6)字串,例如 192.168.0.1/16(其中 192.168.0.1 是 IP 地址,16 是子網掩碼)。以下示例配置了一個 RemoteAddr 路由斷言
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
如果請求的遠端地址為例如 192.168.1.10,則此路由匹配。
修改遠端地址的解析方式
預設情況下,RemoteAddr 路由斷言工廠使用來自傳入請求的遠端地址。如果 Spring Cloud Gateway 位於代理層之後,這可能與實際客戶端 IP 地址不匹配。
您可以透過設定自定義的 RemoteAddressResolver 來定製遠端地址的解析方式。Spring Cloud Gateway 附帶一個非預設的遠端地址解析器,該解析器基於 X-Forwarded-For 請求頭,即 XForwardedRemoteAddressResolver。
XForwardedRemoteAddressResolver 有兩個靜態構造方法,它們採用不同的安全方法
-
XForwardedRemoteAddressResolver::trustAll返回一個RemoteAddressResolver,它始終獲取X-Forwarded-For請求頭中找到的第一個 IP 地址。這種方法容易受到欺騙,因為惡意客戶端可以為X-Forwarded-For設定初始值,該值將被解析器接受。 -
XForwardedRemoteAddressResolver::maxTrustedIndex接受一個索引,該索引與 Spring Cloud Gateway 前面執行的受信任基礎設施的數量相關。例如,如果 Spring Cloud Gateway 只能透過 HAProxy 訪問,則應使用值 1。如果在 Spring Cloud Gateway 可訪問之前需要兩次受信任基礎設施的跳躍,則應使用值 2。
考慮以下請求頭值
X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
以下 maxTrustedIndex 值產生以下遠端地址
maxTrustedIndex |
結果 |
|---|---|
[ |
(無效,初始化時發生 |
1 |
0.0.0.3 |
2 |
0.0.0.2 |
3 |
0.0.0.1 |
[4, |
0.0.0.1 |
以下示例展示瞭如何使用 Java 實現相同的配置
RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
.maxTrustedIndex(1);
...
.route("direct-route",
r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
.uri("https://downstream1")
.route("proxied-route",
r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
.uri("https://downstream2")
)
Weight 路由斷言工廠
Weight 路由斷言工廠接受兩個引數:group 和 weight(一個整數)。權重按組計算。以下示例配置了一個 Weight 路由斷言
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
此路由將把約 80% 的流量轉發到 weighthigh.org,將約 20% 的流量轉發到 weightlow.org
XForwarded Remote Addr 路由斷言工廠
XForwarded Remote Addr 路由斷言工廠接受一個 sources 列表(最小長度為 1),這些源是 CIDR 表示法(IPv4 或 IPv6)字串,例如 192.168.0.1/16(其中 192.168.0.1 是 IP 地址,16 是子網掩碼)。
此路由斷言允許根據 X-Forwarded-For HTTP 請求頭過濾請求。
這可以與負載均衡器或 Web 應用程式防火牆等反向代理一起使用,其中只有當請求來自這些反向代理使用的受信任 IP 地址列表時才允許請求。
以下示例配置了一個 XForwardedRemoteAddr 路由斷言
spring:
cloud:
gateway:
routes:
- id: xforwarded_remoteaddr_route
uri: https://example.org
predicates:
- XForwardedRemoteAddr=192.168.1.1/24
如果 X-Forwarded-For 請求頭包含例如 192.168.1.10,則此路由匹配。