【SpringCloudGateway】SpringCloudGateway路由断言RoutePredicate

一.背景

  最近项目中频繁有使用基于SpringCloudGateway组件开发相关功能,如自定义路由断言,自定义拦过滤器,限流,灰度发布等功能,因此通过文章记录开发过程中的细节和问题点,本篇文档主要记录SpringCloudGateway路由断言

二.什么是路由断言

  路由断言是由SpringCloudGatway三大基本模块(路由,断言,过滤器)中的路由和断言合并而来,参考官网文档 中对于路由和断言的描述
      路由:网关的基本构建块。 它由 ID、目标 URI、断言(谓词)集合和过滤器集合定义。如果聚合断言(谓词)为 true,则匹配路由。  
  断言(谓词):这是一个Java 8 函数谓词。输入类型是 Spring 框架ServerWebExchange。 这使您可以匹配 HTTP 请求中的任何内容,例如标头或参数。
  简而言之就是Gateway根据请求特征抽象出来的一系列具有特定功能的拦截器或处理器,仅允许满足映射关系的请求向后执行,即下图中的Gateway Handler Mapping部分

三.断言工厂

  SpringCloudGateway内置了多个断言工厂供开发者使用:
  The After Route Predicate Factory :  指定日期之后路由断言工厂
  The Before Route Predicate Factory:指定日期之前路由断言工厂
  The Between Route Predicate Factory:指定日期之间路由断言工厂
      The Cookie Route Predicate Factory:Cookie路由断言工厂
      The Method Route Predicate Factory:请求方法路由断言工厂
      The Path Route Predicate Factory:请求路径路由断言工厂
      The Query Route Predicate Factory:查询参数路由断言工厂
      The RemoteAddr Route Predicate Factory:请求IP路由断言工厂
      The Weight Route Predicate Factory:请求权重路由断言工厂
 
  其中使用的比较多的是Path Route Predicate Factory 例如,
  在微服务中常用配置如下
  
spring:
  cloud:
    gateway:
      routes:
      - id: grade_version
        uri: lb://nn-version-servant
        predicates:
        - Path=/speed/gamemaster/gameInfo/version
        filters:
        - StripPrefix=1

  以上配置中 -Path部分即为请求路径断言,表示只有满足该路径的请求才会匹配到当前id为grade_version的路由

  注意:断言也可以配置多个,如下

spring:
  cloud:
    gateway:
      routes:
      - id: grade_version
        uri: lb://nn-version-servant
        predicates:
        - Path=/speed/gamemaster/gameInfo/version
        - RemoteAddr=58.48.225.208
        - Header=reqChannel,1
        filters:
        - StripPrefix=1

  以上配置中Path,RemoteAddr,Header三个断言需要同时满足的请求才会匹配到当前路由

四.自定义断言工厂

  可以看到 SpringCloudGateway内置的多个断言工厂均继承了 AbstractRoutePredicateFactory,断言工厂名称均以RoutePredicateFactory结尾

   我们也可以通过继承该类实现自己的断言工厂NnHeader

@Slf4j
public class NnHeaderRoutePredicateFactory extends AbstractRoutePredicateFactory<NnHeaderRoutePredicateFactory.Config> {

    /**
     * Header key.
     */
    public static final String NN_HEADER_KEY = "header";

    /**
     * Regexp key.
     */
    public static final String NN_REGEXP_KEY = "regexp";

    /**
     * Allow key
     */
    public static final String NN_ALLOW_KEY = "allow";

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

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(NN_HEADER_KEY, NN_REGEXP_KEY, NN_ALLOW_KEY);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            List<String> values = exchange.getRequest().getHeaders().getOrDefault(config.header, Collections.emptyList());
            log.debug("NnHeader匹配规则:{}", JSON.toJSONString(config));
            if (values.isEmpty()) {
                if (config.allow == null) {
                    return false;
                }
                return config.allow;
            }
            if (config.regexp == null) {
                return false;
            }
            return values.stream()
                    .anyMatch(value -> value.matches(String.valueOf(config.regexp)));
        };
    }

    @Validated
    public static class Config {

        @NotEmpty
        private String header;

        private String regexp;

        private Boolean allow;

        public String getHeader() {
            return header;
        }

        public Config setHeader(String header) {
            this.header = header;
            return this;
        }

        public String getRegexp() {
            return regexp;
        }

        public Config setRegexp(String regexp) {
            this.regexp = regexp;
            return this;
        }

        public Boolean getAllow() {
            return allow;
        }

        public Config setAllow(Boolean allow) {
            this.allow = allow;
            return this;
        }
    }
}

  其中Config类三个参数分别是
  header:表示请求头的key
  value: 表示请求头的value
  allow:表示请求头value为空时,是否允许通过

  应用到yaml配置中

spring:
  cloud:
    gateway:
      routes:
      - id: grade_version
        uri: lb://nn-version-servant
        predicates:
        - Path=/speed/gamemaster/gameInfo/version
        - RemoteAddr=58.48.225.208
        - NnHeader=reqChannel,1
        filters:
        - StripPrefix=1

 

五.问题

  1.是否可以配置多个相同的路由断言工厂,例如配置2个Path断言,是否失效?  生效

六.参考

  1.SpringCloudGateway官方文档 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-after-route-predicate-factory
  2.<<SpringCloudAlibaba微服务原理与实战>>

posted @ 2023-12-18 00:48  听风是雨  阅读(98)  评论(0编辑  收藏  举报
/* 看板娘 */