Gateway Request Predicates

Spring Cloud Gateway MVC 作为 Spring WebMvc.fn HandlerMapping 基础架构的一部分匹配路由。Spring Cloud Gateway 重用了 WebMvc.fn 中的许多 RequestPredicate 实现,并包含其他自定义 RequestPredicate 实现。所有这些谓词都匹配 HTTP 请求的不同属性。您可以使用 RequestPredicate.and()RequestPredicate.or() 方法组合多个路由谓词工厂。

The After Request Predicate

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 山地时间(丹佛)之后发送的任何请求。

The Before Request Predicate

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 山地时间(丹佛)之前发送的任何请求。

The Between Request Predicate

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 name 和一个 regexp(它是 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 正则表达式匹配的请求。

The Header Request Predicate

Header 路由谓词工厂接受两个参数,即 header 和一个 regexp(它是 java 正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的标头。以下示例配置一个标头路由谓词:

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+ 正则表达式(即它具有一个或多个数字的值)匹配的标头,则此路由匹配。

The Host Request Predicate

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)作为具有名称和值的地图提取出来,并使用 MvcUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定义的键将其置于 ServerRequest.attributes() 中。这样这些值就可以被 Gateway 处理程序筛选器函数使用了。

The Method Request Predicate

Method 请求谓词采用一个 methods 参数,该参数是一个或多个 HTTP 方法进行匹配。以下示例配置了方法路由谓词:

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();
    }
}

此路由在请求方法为“GET”或“POST”时匹配。

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 时,此路由就会匹配成功。

The Path Request Predicate

Path Request Predicate 采用两个参数:Spring PathPattern patterns 的列表。此 Request Predicate 使用 RequestPredicates.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)作为具有名称和值的地图提取出来,并使用 RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定义的键将其置于 ServerRequest.attributes() 中。这样这些值就可以被 Gateway 处理程序筛选器函数使用了。

提供了一个实用方法(称为 get)以方便访问这些变量。以下示例展示了如何使用 get 方法:

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

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

The Query Request Predicate

Query 路由谓词工厂采用两个参数:必需的 param 和可选的 regexp(它是一个 Java 正则表达式)。以下示例配置了一个查询路由谓词:

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,则上一个路由匹配,因此“green”和“greet”会匹配。

The Weight Request Predicate

Weight 路由谓词工厂采用两个参数:groupweight(一个 int)。权重是按组计算的。以下示例配置了权重路由谓词:

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% 的流量转发到 [role="bare"][role="bare"]https://weighthigh.org,将约 20% 的流量转发到 [role="bare"][role="bare"]https://weightlow.org。