SpringCloud gateway谓词

Posted shigongp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud gateway谓词相关的知识,希望对你有一定的参考价值。

1、After Route Predicate Factory

After路由谓词工厂接受一个参数,一个日期时间(它是一个java ZonedDateTime)。此谓词匹配在指定日期时间之后发生的请求。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai]
          filters:
              - StripPrefix=1

如果时间在2020-01-20T17:42:47.789-07:00[Asia/Shanghai]之后就会处理请求。访问http://localhost:8500/跳转到百度首页。将时间改成2030-01-20T17:42:47.789-07:00[Asia/Shanghai],访问http://localhost:8500/报404错误。

2、The Before Route Predicate Factory

Before路由谓词工厂接受一个参数,一个日期时间(它是一个java ZonedDateTime)。此谓词匹配在指定日期时间之前发生的请求。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Before=2030-01-20T17:42:47.789-07:00[Asia/Shanghai]
          filters:
              - StripPrefix=1

如果时间在2030-01-20T17:42:47.789-07:00[Asia/Shanghai]之前就会处理请求。访问http://localhost:8500/跳转到百度首页。将时间改成2010-01-20T17:42:47.789-07:00[Asia/Shanghai],访问http://localhost:8500/报404错误。

3、The Between Route Predicate Factory

Between路由谓词工厂接受两个参数,datetime1和datetime2,这两个参数是java ZonedDateTime对象。此谓词匹配发生在datetime1之后和datetime2之前的请求。datetime2参数必须在datetime1之后。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Between=2010-01-20T17:42:47.789-07:00[Asia/Shanghai],2030-01-20T17:42:47.789-07:00[Asia/Shanghai]
          filters:
              - StripPrefix=1

如果时间在2010-01-20T17:42:47.789-07:00[Asia/Shanghai]到2030-01-20T17:42:47.789-07:00[Asia/Shanghai]之间则会处理请求。访问http://localhost:8500/跳转百度首页。将时间改成2025-01-20T17:42:47.789-07:00[Asia/Shanghai],2030-01-20T17:42:47.789-07:00[Asia/Shanghai],访问http://localhost:8500/报404.

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

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Cookie=chocolate, ch.p
          filters:
              - StripPrefix=1

用Postman调接口:

可以跳转到百度首页。

将cookie值改为ch.p34在访问报404。

5、The Header Route Predicate Factory

Header路由谓词工厂接受两个参数,Header和regexp(这是一个Java正则表达式)。此谓词与具有给定名称的标头匹配,该名称的值与正则表达式匹配。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Header=X-Request-Id, \\d+
          filters:
              - StripPrefix=1

用postman调用接口:

可以访问百度首页。将123改成123we,在访问报404.

6、The Host Route Predicate Factory

主机路由谓词工厂接受一个参数:主机名模式列表。该模式是Ant样式的模式。作为分离器。此谓词与匹配模式的Host请求头相匹配。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Host=**.somehost.org,**.anotherhost.org
          filters:
              - StripPrefix=1

用postman调用:

可以跳转百度首页。将Host头的值改成beta.somehost.org和www.anotherhost.org,也能访问。

7、The Method Route Predicate Factory

方法路由谓词工厂接受一个方法参数,该参数是一个或多个参数:要匹配的HTTP方法。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: http://www.baidu.com
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Method=GET,POST
          filters:
              - StripPrefix=1

用Postman调用,以get和post分别调用都能跳转百度首页。改成PUT方式报404。

8、 The Path Route Predicate Factory

路径路由谓词工厂采用两个参数:一个是Spring PathMatcher模式列表,另一个是名为matchTrailingFlash的可选标志(默认为true)。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: lb://producer
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Path=/producer/**
          filters:
              - StripPrefix=1

如果访问路径是/producer/**模式就会转发到producer服务,lb表示负载均衡。启动EurekaServer,两个producer服务。同时在gateway模块加依赖:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>

gateway负载均衡是使用spring-cloud-starter-loadbalancer实现的。

访问http://localhost:8500/producer/hello,可以看到端口出现变化。

9、 The Query Route Predicate Factory

查询路由谓词工厂接受两个参数:一个必需的param和一个可选的regexp(这是一个Java正则表达式)。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: lb://producer
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Query=green
          filters:
              - StripPrefix=1

只有查询参数有green就会处理请求。访问http://localhost:8500/producer/hello报404。访问http://localhost:8500/producer/hello?green=123,成功。

 

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: lb://producer
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - Query=red, gree.
          filters:
              - StripPrefix=1

查询参数名为red,参数值匹配正则表达式gree.的请求才会被处理。访问http://localhost:8500/producer/hello?red=green,成功。访问http://localhost:8500/producer/hello?red=grenn报404.

10、The RemoteAddr Route Predicate Factory

RemoteAddr路由谓词工厂采用源列表(最小大小为1),这些源是CIDR表示法(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。例如:

spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: Goods-Server  # 路由 id,唯一标识
          uri: lb://producer
          predicates:
           #   - Path=/**  # 断言,路由匹配条件,匹配 /product 开头的所有 api
            - RemoteAddr=192.168.1.1/24
          filters:
              - StripPrefix=1

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

11、The Weight Route Predicate Factory

Weight路由谓词工厂接受两个参数:group和Weight(一个int)。权重按每组计算。例如:

spring:
  cloud:
    gateway:
      routes:
        - id: weight_high
          uri: http://localhost:8002
          predicates:
            - Weight=group1, 8
          filters:
              - StripPrefix=1
        - id: weight_low
          uri: http://localhost:8004
          predicates:
            - Weight=group1, 2
          filters:
              - StripPrefix=1

启动了两个producer,一个端口是8002,一个端口是8004。访问http://localhost:8500/producer/hello这个地址10次,端口是8002的producer接收请求8次,端口是8004的producer接收请求2次。

008-spring cloud gateway-路由谓词RoutePredicateRoutePredicateFactory

一、概述

  Spring Cloud Gateway将路由作为Spring WebFlux HandlerMapping基础结构的一部分进行匹配。 Spring Cloud Gateway包含许多内置的Route Predicate Factories。所有这些谓词都匹配HTTP请求的不同属性。多路线谓词工厂可以组合,并通过逻辑and。

  路由选择是通过Predicate函数式接口进行判断当前路由是否满足给定条件。

  附注:关于jdk8的Predicate
  Predicate<T> 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
add--与、or--或、negate--非   boolean test(T t); 判断   Predicate<T> and(Predicate<? super T> other) 接收一个Predicate类型,也就是将传入的条件和当前条件以并且(AND)的关系组合   Predicate<T> or(Predicate<? super T> other)接收一个Predicate类型,也就是将传入的条件和当前条件以或(OR)的关系组合   更多参看:https://www.cnblogs.com/bjlhx/p/9711292.html

1.1、路由谓词创建及使用

1️⃣、加载路由中的Predicate

  在路由定位器中以及看到了通过路由定义转换路由方法,其中包含了通过谓语定义(PredicateDefinition)转换谓语(Predicate)的部分,在RouteDefinitionRouteLocator类中源码如下:
/**
     * 返回组合的谓词
     * @param routeDefinition
     * @return
     */
    private Predicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
        //获取RouteDefinition中的PredicateDefinition集合
        List<PredicateDefinition> predicates = routeDefinition.getPredicates();

        Predicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));

        for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {
            Predicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
            //返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND
            predicate = predicate.and(found);
        }

        return predicate;
    }
    
        /**
     * 获取一个谓语定义(PredicateDefinition)转换的谓语
     * @param route
     * @param predicate
     * @return
     */
    @SuppressWarnings("unchecked")
    private Predicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
        //获取谓语创建工厂
        RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
        if (factory == null) {
            throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());
        }
        //获取参数
        Map<String, String> args = predicate.getArgs();
        if (logger.isDebugEnabled()) {
            logger.debug("RouteDefinition " + route.getId() + " applying "
                    + args + " to " + predicate.getName());
        }

        //组装参数
        Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
        //构建创建谓语的配置信息
        Object config = factory.newConfig();
        ConfigurationUtils.bind(config, properties,
                factory.shortcutFieldPrefix(), predicate.getName(), validator);
        if (this.publisher != null) {
            this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));
        }
        //通过谓语工厂构建谓语
        return factory.apply(config);
    }
  • 获取路由定义(routeDefinition)所有的谓语定位(PredicateDefinition)
  • 以此根据谓语定义(PredicateDefinition)查找谓语对于的创建工厂(RoutePredicateFactory) 创建谓语
  • 通过 Predicate<T>接口 and方法合并谓语集合返回一个新的复合谓语

2️⃣、使用路由Predicate判断路由是否可用

  在Spring-Cloud-Gateway之请求处理流程里,在handlerMapping中通过路由定位器获取所有路由,并过滤掉谓语判断失败的路由,最终获取满足条件的路由
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
        //通过路由定位器获取路由信息
        return this.routeLocator.getRoutes()
                .filter(route -> {
            exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, route.getId());
                    //返回通过谓语过滤的路由信息
                    return route.getPredicate().test(exchange);
                });
    }

  通过上面两步可以看到了整个路由的条件创建以及使用的地方以及流程,Spring-Cloud-Gateway通过Predicate接口完成简单条件组合以及判断。

1.2、RoutePredicateFactory 路由谓词工厂

  Spring-Cloud-Gateway通过RoutePredicateFactory创建Predicate。其中预制了很多RoutePredicateFactory使其可以通过简单的配置就可以创建出理想的Predicate。
查看类Uml图
  

按照子类功能划分:

  

1️⃣、MethodRoutePredicateFactory

/**
 * 请求方式(GET,POST,DEL,PUT)校验匹配创建工厂
 */
public class MethodRoutePredicateFactory extends AbstractRoutePredicateFactory<MethodRoutePredicateFactory.Config> {

    public static final String METHOD_KEY = "method";
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            //获取当前请求的HttpMethod
            HttpMethod requestMethod = exchange.getRequest().getMethod();
            //校验请求HttpMethod与配置是否一致
            return requestMethod == config.getMethod();
        };
    }

    public static class Config {
        /**
         * http 请求Method
         */
        private HttpMethod method;

        public HttpMethod getMethod() {
            return method;
        }

        public void setMethod(HttpMethod method) {
            this.method = method;
        }
    }
}

配置示例

spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET

过程:

  • Method=GET 会被解析成PredicateDefinition对象 (name =Method ,args= GET)
  • 通过PredicateDefinition的Name找到MethodRoutePredicateFactory工厂
  • 通过 PredicateDefinition 的args 创建Config对象(HttpMethod=GET)
  • 通过 MethodRoutePredicateFactory工厂的apply方法传入config创建Predicate对象。

1.3、全部谓词配置

1.3.1、After Route Predicate Factory

  此谓词匹配当前日期时间之后发生的请求。

  application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: http://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

1.3.2、Before Route Predicate Factory

  此谓词匹配在当前日期时间之前发生的请求。

  application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: http://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

1.3.3、Between Route Predicate Factory

  此谓词匹配datetime1之后和datetime2之前发生的请求。 datetime2参数必须在datetime1之后。

  application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: http://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

1.3.4、Cookie Route Predicate Factory

  Cookie Route Predicate Factory有两个参数,cookie名称和正则表达式。此谓词匹配具有给定名称且值与正则表达式匹配的cookie。

  application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Cookie=chocolate, ch.p

  此路由匹配请求有一个名为chocolate的cookie,其值与ch.p正则表达式匹配。

1.3.5、Header Route Predicate Factory

  Header Route Predicate Factory有两个参数,标题名称和正则表达式。此谓词与具有给定名称且值与正则表达式匹配的标头匹配。

  application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: http://example.org
        predicates:
        - Header=X-Request-Id, \\d+

  如果请求具有名为X-Request-Id的标头,则该路由匹配,其值与\\ d +正则表达式匹配(具有一个或多个数字的值)。

1.3.6、Host Route Predicate Factory

  Host Route Predicate Factory采用一个参数:主机名模式。该模式是一种Ant样式模式“.”作为分隔符。此谓词匹配与模式匹配的Host标头。

  application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Host=**.somehost.org

  如果请求的主机头具有值www.somehost.org或beta.somehost.org,则此路由将匹配。

1.3.7、Method Route Predicate Factory

   Method Route Predicate Factory采用一个参数:要匹配的HTTP方法。

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET

1.3.8、Path Route Predicate Factory

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment}

/foo/1 or /foo/bar.

1.3.9、Query Route Predicate Factory

Query Route Predicate Factory有两个参数:一个必需的参数和一个可选的正则表达式。

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=baz

如果请求包含baz查询参数,则此路由将匹配。

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=foo, ba.

如果请求包含其值与ba匹配的foo查询参数,则此路由将匹配。 regexp,所以bar和baz匹配。

1.3.10、RemoteAddr Route Predicate Factory

RemoteAddr Route Predicate Factory采用CIDR符号(IPv4或IPv6)字符串的列表(最小值为1),例如, 192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

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

以上是关于SpringCloud gateway谓词的主要内容,如果未能解决你的问题,请参考以下文章

008-spring cloud gateway-路由谓词RoutePredicateRoutePredicateFactory

Spring Cloud Alibaba - 26 Gateway-自定义谓词工厂

Spring Cloud Alibaba - 25 Gateway-路由断言工厂Route Predicate Factories谓词工厂示例及源码解析

SpringCloud GateWay 万字详解

SpringCloud集成Gateway

springcloud-gateway 网关异常处理