Spring Cloud Gateway网关之自定义路由谓词工厂

API网关
01 Spring Cloud Gateway网关之快速上手
02 Spring Cloud Gateway网关之两种路由配置方式
03 Spring Cloud Gateway网关之跨域支持
04 Spring Cloud Gateway网关之自定义全局过滤器
05 Spring Cloud Gateway网关之自定义路由过滤器
06 Spring Cloud Gateway网关之自定义路由谓词工厂
07 Spring Cloud Gateway网关之超时时间配置
08 Spring Cloud Gateway网关之配置说明
09 Zuul网关之快速上手
10 Zuul网关之路由配置
11 Zuul网关之跨域支持
12 Zuul网关之自定义过滤器
13 Zuul网关之超时时间配置

一 何为路由谓词工厂(Route Predicate Factories)

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。 Spring Cloud Gateway包括许多内置的路由谓词工厂。所有这些谓词都与HTTP请求的不同属性匹配。可以将多个路由谓词工厂与逻辑和语句结合使用。

二 框架自带了哪些路由谓词工厂

  • After RoutePredicateFactory

    AfterRoutePredicateFactory接收一个参数,即datetime(这是一个Java ZonedDateTime)。该谓词匹配在指定日期时间之后发生的请求。如以下示例配置:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: after_route
    uri: https://example.org
    predicates:
    - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  • Before RoutePredicateFactory

    BeforeRoutePredicateFactory接收一个参数,即datetime(这是一个Java ZonedDateTime)。该谓词匹配在指定日期时间之前发生的请求。如以下示例配置:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: before_route
    uri: https://example.org
    predicates:
    - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
  • Between RoutePredicateFactory

    BetweenRoutePredicateFactory接收两个参数datetime1datetime2,它们是java ZonedDateTime对象。该谓词匹配在datetime1之后和datetime2之前发生的请求。 datetime2参数必须在datetime1之后。如以下示例配置:

    1
    2
    3
    4
    5
    6
    7
    8
    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]
  • Cookie RoutePredicateFactory

    CookieRoutePredicateFactory接收两个参数,即cookie name和一个regexp(这是Java正则表达式)。该谓词匹配具有给定名称且其值与正则表达式匹配的cookie。以下示例配置Cookie路由谓词工厂:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: cookie_route
    uri: https://example.org
    predicates:
    - Cookie=chocolate, ch.p
  • Header RoutePredicateFactory

    HeaderRoutePredicateFactory接收两个参数,请求头的name和一个regexp(这是Java正则表达式)。该谓词与具有给定名称的请求头匹配,该请求头的值与正则表达式匹配。以下示例配置标头路由谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: header_route
    uri: https://example.org
    predicates:
    - Header=X-Request-Id, \d+
  • Host RoutePredicateFactory

    HostRoutePredicateFactory接收一个参数,即主机名列表patterns,该patterns是带有的Ant样式的模式。作为分隔符。该谓词与匹配模式的Host请求头匹配。以下示例配置主机路由谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: host_route
    uri: https://example.org
    predicates:
    - Host=**.somehost.org,**.anotherhost.org

    还支持URI模板变量(例如{sub} .myhost.org),以上示例如果请求的主机请求头的值为www.somehost.org或beta.somehost.org或www.anotherhost.org,则此路由匹配。

    他的谓词提取URI模板变量(如上例中定义的sub)作为名称和值的映射,并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放置在ServerWebExchange.getAttributes()中。这些值可供GatewayFilter工厂使用。

  • Method RoutePredicateFactory

    MethodRoutePredicateFactory 接收methods参数,该参数是一个或多个参数:要匹配的HTTP方法。以下示例配置方法route谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: method_route
    uri: https://example.org
    predicates:
    - Method=GET,POST

    此示例,如果请求方法是GET或POST,则此路由匹配。

  • Path RoutePredicateFactory

    PathRoutePredicateFactory是路径路由谓词工厂,在实际生产中是用的最多的,接收两个参数:Spring PathMatcher patterns列表和一个称为matchOptionalTrailingSeparator的可选标志。以下示例配置路径路由谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: path_route
    uri: https://example.org
    predicates:
    - Path=/red/{segment},/blue/{segment}

    该谓词提取URI模板变量(如上例中定义的segment)作为名称和值的映射,并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放置在ServerWebExchange.getAttributes()中。这些值可供GatewayFilter工厂使用。访问该变量的方式如下

    1
    2
    Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
    String segment = uriVariables.get("segment");
  • Query RoutePredicateFactory

    QueryRoutePredicateFactory是根据查询参数匹配的路由谓词工厂,接收两个参数:必需的param和可选的regexp(这是Java正则表达式)。以下示例配置查询路由谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: query_route
    uri: https://example.org
    predicates:
    - Query=green

    如果请求包含green 查询参数,则前面的路由匹配。

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: query_route
    uri: https://example.org
    predicates:
    - Query=red, gree.

    如上示例,如果查询参数包含 red ,并且其值与 gree. 正则匹配,如 greengreet 都会被匹配。

  • RemoteAddr RoutePredicateFactory

    RemoteAddrRoutePredicateFactory接收一个参数sources列表(最小大小为1),这些sources是CIDR标记(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,而16是子网掩码) )。下面的示例配置RemoteAddr路由谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: remoteaddr_route
    uri: https://example.org
    predicates:
    - RemoteAddr=192.168.1.1/24

    如果请求的远程地址是例如192.168.1.10,则此路由匹配。

  • Weight RoutePredicateFactory

    WeightRoutePredicateFactory是权重路由谓词工厂,接收两个参数:groupweight(一个int)。权重是按组计算的。以下示例配置权重路由谓词:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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。

    默认情况下,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前面运行的受信任基础结构的数量相关。例如,如果只能通过HAProxy访问Spring Cloud Gateway,则应使用值1。如果在访问Spring Cloud Gateway之前需要两跳可信基础架构,则应使用值2。

    Forwarded了多次的,如以下请求头,和maxTrustedIndex对应关系

    1
    2
    > X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
    >
maxTrustedIndexresult
[Integer.MIN_VALUE,0](invalid, IllegalArgumentException during initialization)
10.0.0.3
20.0.0.2
30.0.0.1
[4, Integer.MAX_VALUE]0.0.0.1

三 自定义路由谓词工厂

路由谓词工厂的定义与路由过滤器的定义非常相似,我们只需要继承AbstractRoutePredicateFactory<Config>,并重写里面的方法apply方法即可。apply方法重写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
// 条件判断 ...
}

@Override
public String toString() {
// 重写toString方法
}
};
}

定义快捷方式配置写法的字段顺序,重写以下方法:

1
2
3
4
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("字段名1", "字段名2");
}

其中的Config一般是自定义过滤器工厂的静态内部类,主要是定义传递的参数,如

1
2
3
4
5
6
7
8
9
10
public static class Config {
@NotNull
private ZonedDateTime datetime;
public ZonedDateTime getDatetime() {
return datetime;
}
public void setDatetime(ZonedDateTime datetime) {
this.datetime = datetime;
}
}

一个示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

public MyRoutePredicateFactory() {
super(Config.class);
}

@Override
public Predicate<ServerWebExchange> apply(Config config) {
// grab configuration from Config object
return exchange -> {
//grab the request
ServerHttpRequest request = exchange.getRequest();
//take information from the request to see if it
//matches configuration.
return matches(config, request);
};
}

public static class Config {
//Put the configuration properties for your filter here
}

}