閘道請求斷言

Spring Cloud Gateway MVC 將路由比對作為 Spring WebMvc.fn HandlerMapping 基礎架構的一部分。Spring Cloud Gateway 重複使用了 WebMvc.fn 中的許多 RequestPredicate 實作,並包含其他自訂的 RequestPredicate 實作。所有這些斷言都比對 HTTP 請求的不同屬性。您可以將多個路由斷言工廠與 RequestPredicate.and()RequestPredicate.or() 方法結合使用。

After 請求斷言

After 路由斷言工廠接受一個參數,即 datetime(java ZonedDateTime)。此斷言比對在指定 datetime 之後發生的請求。以下範例設定了一個 after 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: after_route
          uri: https://example.org
          predicates:
          - After=2017-01-20T17:42:47.789-07:00[America/Denver]
GatewaySampleApplication.java
import java.time.ZonedDateTime;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.after;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsAfter() {
		return route("after_route")
			.route(after(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]")), http("https://example.org"))
			.build();
    }
}

此路由比對在 2017 年 1 月 20 日 17:42 山區時間(丹佛)之後發出的任何請求。

Before 請求斷言

Before 路由斷言工廠接受一個參數,即 datetime(java ZonedDateTime)。此斷言比對在指定的 datetime 之前發生的請求。以下範例設定了一個 before 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: before_route
          uri: https://example.org
          predicates:
          - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
GatewaySampleApplication.java
import java.time.ZonedDateTime;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.before;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsBefore() {
		return route("before_route")
			.route(before(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]")), http("https://example.org"))
			.build();
    }
}

此路由比對在 2017 年 1 月 20 日 17:42 山區時間(丹佛)之前發出的任何請求。

Between 請求斷言

Between 路由斷言工廠接受兩個參數,datetime1datetime2,它們是 java ZonedDateTime 物件。此斷言比對在 datetime1 之後和 datetime2 之前發生的請求。datetime2 參數必須在 datetime1 之後。以下範例設定了一個 between 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        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]
GatewaySampleApplication.java
import java.time.ZonedDateTime;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.between;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsBetween() {
		return route("between_route")
			.route(between(ZonedDateTime.parse("2017-01-20T17:42:47.789-07:00[America/Denver]"), ZonedDateTime.parse("2017-01-21T17:42:47.789-07:00[America/Denver]")), http("https://example.org"))
			.build();
    }
}

此路由比對在 2017 年 1 月 20 日 17:42 山區時間(丹佛)之後和 2017 年 1 月 21 日 17:42 山區時間(丹佛)之前發出的任何請求。這對於維護視窗可能很有用。

Cookie 路由斷言工廠接受兩個參數,cookie nameregexp(Java 正則表達式)。此斷言比對具有給定名稱且其值與正則表達式匹配的 cookie。以下範例設定了一個 cookie 路由斷言工廠

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: cookie_route
          uri: https://example.org
          predicates:
          - Cookie=chocolate, ch.p
GatewaySampleApplication.java
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.between;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCookie() {
		return route("cookie_route")
			.route(cookie("chocolate", "ch.p"), http("https://example.org"))
			.build();
    }
}

此路由比對具有名為 chocolate 的 cookie,其值與 ch.p 正則表達式匹配的請求。

Header 請求斷言

Header 路由斷言工廠接受兩個參數,headerregexp(Java 正則表達式)。此斷言比對具有給定名稱且其值與正則表達式匹配的標頭。以下範例設定了一個 header 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: header_route
          uri: https://example.org
          predicates:
          - Header=X-Request-Id, \d+
GatewaySampleApplication.java
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.header;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCookie() {
		return route("cookie_route")
			.route(header("X-Request-Id", "\\d+"), http("https://example.org"))
			.build();
    }
}

如果請求具有名為 X-Request-Id 的標頭,且其值與 \d+ 正則表達式(即,它具有一個或多個數字的值)匹配,則此路由會匹配。

Host 請求斷言

Host 路由斷言工廠接受一個參數:主機名稱 patterns 的列表。模式是使用 . 作為分隔符的 Ant 樣式模式。此斷言比對與模式匹配的 Host 標頭。以下範例設定了一個 host 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: host_route
          uri: https://example.org
          predicates:
          - Host=**.somehost.org,**.anotherhost.org
GatewaySampleApplication.java
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsHost() {
		return route("host_route")
			.route(host("**.somehost.org", "**.anotherhost.org"), http("https://example.org"))
			.build();
    }
}

也支援 URI 範本變數(例如 {sub}.myhost.org)。

如果請求具有 Host 標頭,其值為 www.somehost.orgbeta.somehost.orgwww.anotherhost.org,則此路由會匹配。

此斷言提取 URI 範本變數(例如,前面範例中定義的 sub)作為名稱和值的映射,並將其放置在 ServerRequest.attributes() 中,並使用 MvcUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定義的鍵。這些值隨後可供閘道處理器篩選器函數使用。

Method 請求斷言

Method 請求斷言接受 methods 參數,它是一個或多個參數:要比對的 HTTP 方法。以下範例設定了一個 method 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: method_route
          uri: https://example.org
          predicates:
          - Method=GET,POST
GatewaySampleApplication.java
import org.springframework.http.HttpMethod;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.method;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsMethod() {
		return route("method_route")
			.route(method(HttpMethod.GET, HttpMethod.POST), http("https://example.org"))
			.build();
    }
}

如果請求方法是 GETPOST,則此路由會匹配。

GatewayRequestPredicates.methodRequestPredicates.methods 的簡單別名。此外,RouterFunctions.Builder API 包含方便的方法,可將 methodpath RequestPredicates 結合使用。

GatewaySampleApplication.java
import org.springframework.http.HttpMethod;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.methods;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsMethod() {
		return route("method_route")
			.GET("/mypath", http("https://example.org"))
			.build();
    }
}

如果請求方法是 GET 且路徑是 /mypath,則此路由會匹配。

Path 請求斷言

Path 請求斷言接受兩個參數:Spring PathPattern patterns 的列表。此請求斷言使用 RequestPredicates.path() 作為底層實作。以下範例設定了一個 path 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: path_route
          uri: https://example.org
          predicates:
          - Path=/red/{segment},/blue/{segment}
GatewaySampleApplication.java
import org.springframework.http.HttpMethod;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.method;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsPath() {
		return route("path_route")
			.route(path("/red/{segment}", "/blue/{segment}"), http("https://example.org"))
			.build();
    }
}

如果請求路徑是例如:/red/1/red/1//red/blue/blue/green,則此路由會匹配。

此斷言提取 URI 範本變數(例如,前面範例中定義的 segment)作為名稱和值的映射,並將其放置在 ServerRequest.attributes() 中,並使用 RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定義的鍵。這些值隨後可供閘道處理器篩選器函數使用。

一個公用程式方法(稱為 get)可用於更輕鬆地存取這些變數。以下範例示範如何使用 get 方法

Map<String, Object> uriVariables = MvcUtils.getUriTemplateVariables(request);

String segment = uriVariables.get("segment");

Query 請求斷言

Query 路由斷言工廠接受兩個參數:必要的 param 和可選的 regexp(Java 正則表達式)。以下範例設定了一個 query 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: query_route
          uri: https://example.org
          predicates:
          - Query=green
GatewaySampleApplication.java
import org.springframework.http.HttpMethod;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.query;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsQuery() {
		return route("query_route")
			.route(query("green"), http("https://example.org"))
			.build();
    }
}

如果請求包含 green 查詢參數,則前面的路由會匹配。

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: query_route
          uri: https://example.org
          predicates:
          - Query=red, gree.
GatewaySampleApplication.java
import org.springframework.http.HttpMethod;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.query;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsQuery() {
		return route("query_route")
			.route(query("red", "gree."), http("https://example.org"))
			.build();
    }
}

如果請求包含 red 查詢參數,且其值與 gree. regexp 匹配,則前面的路由會匹配,因此 greengreet 會匹配。

Weight 請求斷言

Weight 路由斷言工廠接受兩個參數:groupweightint)。權重是按群組計算的。以下範例設定了一個 weight 路由斷言

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: weight_high
          uri: https://weighthigh.org
          predicates:
          - Weight=group1, 8
        - id: weight_low
          uri: https://weightlow.org
          predicates:
          - Weight=group1, 2
GatewaySampleApplication.java
import org.springframework.http.HttpMethod;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.method;

@Configuration
class RouteConfiguration {

	@Bean
	public RouterFunction<ServerResponse> gatewayRouterFunctionsWeights() {
		return route("weight_high")
				.route(weight("group1", 8).and(path("/**")), http("https://weighthigh.org"))
				.build().and(
			route("weight_low")
				.route(weight("group1", 2).and(path("/**")), http("https://weightlow.org"))
				.build());
	}
}

此路由會將約 80% 的流量轉發到 weighthigh.org,將約 20% 的流量轉發到 weightlow.org