Spring Cloud Gateway Route Predicate Factory 的使用

本文记录了Spring Cloud Gateway的一些用法,介绍其基本组成,包括Route路由、Predicate谓语、Filter过滤器等核心概念及工作原理。详细阐述了网关Predicate的配置方式,列举多种Route Predicate Factories的使用,还说明了如何自己编写一个route predicate factory,并给出完整代码链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、需求

记录Spring Cloud Gateway的一些用法,不对其原理进行过多的探究。

二、基本组成

1、简介

Spring Cloud Gateway 是 基于Spring boot 5Spring Boot 2.0Project Reactor 等技术开发的网关。它旨在为微服务提供一个简单有效的方式来管理api路由。

Spring Cloud Gateway 是基于 Netty 运行的,不能运行在传统的Servlet容器中作为War包运行。

2、核型概念

1、Route 路由

Route是网关的基本组成单元,它是有一个ID,一个目标URI和一组predicates和一组filters组成,如果一组断言结果为真,则匹配路由,目标URI会被访问。
注意:
1、多个 Predicate 之间是 逻辑and 的关系。
2、多个Predicate是从定义的顺序从上到下依次执行,也可以指定 order 属性的值。

2、Predicate 谓语、断言

Predicate 是Java 8 Function interface。输入类型是Spring Framework ServerWebExchange。可以用来匹配HTTP请求中的任何内容,例如headers 或者 parameters

3、Filter 过滤器

FilterGatewayFilter的实例。通过Filter我们可以在请求发送或返回下游服务时 修改 请求响应

3、工作原理

Spring Cloud Gateway的工作原理
上图来自 Spring 官网。

三、网关 Predicate配置方式

1、快捷配置方式(配置文件)

快捷方式是由过滤器是的名称识别,后面紧跟=,在跟以逗号(,)分隔的参数值。

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

上一个示例使用两个参数定义了Cookie Route Predicate Factory,这两个参数是cookie名称,mycookie和与mycookievalue匹配的值

2、完全展开的参数(配置文件)

name:指定谓词工厂的名字
args:指定对应谓词工厂中的参数对应的值。

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

这种方式配置和上面的快捷方式配置的是一个意思

3、上方2种方式配置和代码对应关系

上方2种方式配置和代码对应关系

4、uri 值的方式

1、以http开头

当匹配到这个路由后,会跳转到这个地址。

2、以 lb 开头

eg:
     uri: lb://service-name
解释:
lb:表示负载均衡的意思
service-name:值的是调用服务在注册中心注册的服务名。

四、Route Predicate Factories

Spring Cloud Gateway内置了特别多的路由谓词工厂,用来匹配http请求。当多个一起使用时,是and的关系,即需要所有的谓词工厂都匹配,才匹配这个路由。

1、After

1、描述:

当前请求在指定时间之后才匹配

2、存在参数:

    datetime 数据类型是 ZonedDateTime,带有时区

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - After=2020-11-01T11:05:08.020+08:00[Asia/Shanghai]

2、Before

1、描述:

当前请求在指定时间之前才匹配

2、存在参数:

    datetime 数据类型是 ZonedDateTime,带有时区

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Before=2020-11-01T11:05:08.020+08:00[Asia/Shanghai]

3、Between

1、描述:

当前请求在指定时间中间才匹配

2、存在参数:

    datetime1 数据类型是 ZonedDateTime,带有时区
    datetime2 数据类型是 ZonedDateTime,带有时区
     并且 datetime1 必须< datetime2

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Between=2020-11-01T11:08:08.020+08:00[Asia/Shanghai],2020-11-01T11:15:08.020+08:00[Asia/Shanghai]

4、Cookie

1、描述:

当前请求中的cookie值匹配配置的cookie参数值时生效

2、存在参数:

    name 请求cookie中的参数的名字
    regexp 请求cookie中的参数的值,配置的值是Java中的正则表达式形式。

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Cookie=token,tokenvalue\d+

实例

4、解释

  • Cookie=token,tokenvalue\d+
    表示 请求中必须存在一个 cookie 的key 是 token 的,且值必须是 tokenvalue 后面加上一个数子才匹配的上,否则匹配不上。

5、Header

1、描述:

当前请求中的header值匹配配置的header参数值时生效

2、存在参数:

    name header key的名字
    regexp header key对应的值,配置的Java中的正则表达式形式

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Header=X-Token-Id,\d+

4、解释

  • Header=X-Token-Id,\d+
    表示请求头中必须存在R-Token-Id且它的值必须是数字

6、Host

1、描述:

匹配请求头中的Host的值

2、存在参数:

    patterns 配置一系列的以.作为分隔的ant风格host地址,多个中间以,隔开。Host中配置的值还支持URI template variables,比如{xxx}.baidu.com

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Host=**.gateway.com,{study}.baidu.com

Host匹配

4、解释

  • Host=**.gateway.com,{study}.baidu.com
    1、**.gateway.com:表示请求中的Host的值需要配置这种ant风格
    2、{study}.baidu.comstudy这个模版变量可以在GatewayFilter中获取到,通过ServerWebExchange.getAttributes().get(ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE)获取

7、Method

1、描述:

匹配请求头中的Method的值

2、存在参数:

    methods 需要匹配的方法,比如GETPOST

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Method=GET,POST,PUT # 只有get,post,put请求才能匹配上方这个路由

8、Path

1、描述:

匹配请求路径。

2、存在参数:

    patterns 需要匹配的路径eg: /product/{id},/product/**
    matchOptionalTrailingSeparator 一个可选的参数

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - Path=/product/findOne/{productId},/product/**

4、解释

/product/findOne/{productId} 支持uri模版变量,productId可以在GatewayFilter中获取,获取方式.

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("productId");

9、Query

1、描述:

匹配请求参数。

2、存在参数:

    param 请求参数的key值
    regexp 请求参数的值,配置的值是Java中的正则表达式形式。

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            #- Query=pwd
            - Query=username,\d+

4、解释

1、Query=pwd 表示请求中必须存在 pwd这个请求参数
2、Query=username,\d+ 表示请求中必须存在username这个参数,且它的值必须是数字

10、RemoteAddr

1、描述:

匹配请求的ip地址,支持ipv4和ipv6。

2、存在参数:

    sources 地址列表eg:127.0.0.1/16 后方的/16是子网掩码

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider # 名字唯一即可
          uri: lb://product-provider
          predicates:
            - RemoteAddr=127.0.0.1/16

4、注意

如果我们的Spring Cloud Gateway是位于代理后面,那么获取到远程地址可能不正确,此时我们可以自己编写一个RemoteAddressResolver来解决。

参考链接:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#the-weight-route-predicate-factory

11、Weight

1、描述:

根据权重来分发请求,权重是根据group来计算的。

2、存在参数:

    group 组,权重根据组来计算
    weight 权重值,是一个 Int 的值

3、配置实例

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider
          uri: https://weighthigh.org
          predicates:
            - Weight=group1,8
        - id: user-consumer
          uri: https://weightlow.org
          predicates:
            - Weight=group1,2

4、解释

上方配置会导致80%的请求落到 https://weighthigh.org,有20%的请求落到https://weightlow.org

五、自己编写一个 route predicate factory

1、编写步骤

1、编写一个类,实现RoutePredicateFactory接口,或继承AbstractRoutePredicateFactory
    > 1、AbstractRoutePredicateFactory 中的 C 表示 配置文件类
    > 2、重写shortcutFieldOrder此方法,表示的配置文件中参数的位置
    > 3、重写apply(C c)方法,表示的是具体的业务逻辑
2、我们自己编写的类必须要以RoutePredicateFactory结尾,否则比较麻烦,参考
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#initFactories 这个方法。

2、要实现的功能

判断请求参数中是否存在 token 配置的值。

3、Java代码

@Slf4j
@Component
public class TokenRoutePredicateFactory extends AbstractRoutePredicateFactory<TokenRoutePredicateFactory.Config> {

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

    @Override
    public List<String> shortcutFieldOrder() {
        return Lists.newArrayList("token");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            log.info("判断请求头中是否存在token这个参数");
            String token = exchange.getRequest().getQueryParams().getFirst(config.getToken());
            return StringUtils.isNotBlank(token);
        };
    }

    @Data
    public static class Config {
        private String token;
    }
}

4、配置文件

spring:
  cloud:
    gateway:
      routes:
        - id: product-provider
          uri: lb://product-provider
          predicates:
            - Token=token

5、解释

Java 编写一个 Route Predicate Factory

六、完整代码

https://gitee.com/huan1993/spring-cloud-alibaba-parent/tree/master/gateway

七、参考链接

https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/

<think>好的,我现在需要回答用户关于如何使用Spring Cloud Gateway内置的GatewayFilterFactory来校验请求是否携带某个请求头的问题。首先,我应该回忆一下Spring Cloud Gateway的相关知识,特别是内置的过滤器工厂。 首先,用户的问题是关于请求头校验的,所以需要确定是否有现成的过滤器工厂可以实现这个功能。我记得Spring Cloud Gateway提供了许多内置的过滤器工厂,比如AddRequestHeader、RemoveRequestHeader等,但具体哪个用于校验请求头呢? 可能需要使用到断言(Predicate)而不是过滤器(Filter),因为校验更类似于路由判断的条件。不过用户明确提到了GatewayFilterFactory,所以可能需要进一步确认。或者,是否存在一个过滤器可以在请求头不存在时进行拦截,比如返回错误状态码。 或者,可能用户希望当请求头不存在时,网关能够拒绝请求,这时可能需要自定义一个过滤器,或者使用现有的过滤器来检查请求头。例如,使用Header断言,但断言通常用于路由判断,而过滤器用于处理请求。不过,用户提到的是GatewayFilterFactory,所以应该寻找相关的过滤器。 查阅Spring Cloud Gateway文档,发现有一个名为Header的GatewayFilterFactory,但它的作用可能是添加或修改请求头,而不是校验。另一个可能是使用ModifyRequestBody或类似的过滤器,但这可能不适用。 或者,可能需要使用Pre类型的过滤器,在转发之前检查请求头是否存在,如果不存在则返回错误。这时可能需要自定义一个过滤器,但用户问的是内置的GatewayFilterFactory,所以是否有内置的实现呢? 可能用户的需求可以通过结合断言和过滤器来实现。例如,使用Header路由断言来确保只有带有特定请求头的请求才能被路由,否则返回404。但用户可能希望返回更具体的状态码,比如400,这时候可能需要自定义逻辑。 不过,用户的问题明确提到使用内置的GatewayFilterFactory来校验请求头是否存在。如果没有现成的过滤器,可能需要使用断言来处理,或者用户可能需要自定义过滤器。但根据我的记忆,可能有一个内置的过滤器可以实现这个功能,比如使用SetStatus GatewayFilterFactory,当请求头不存在时设置响应状态码。 或者,使用RedirectTo过滤器来重定向,但这可能不太合适。或者,使用一个过滤器来检查请求头,并在不存在时抛出异常,进而由错误处理机制处理。 可能需要进一步确认Spring Cloud Gateway的内置过滤器列表。例如,有一个名为RequestHeader的过滤器工厂,可能用于操作请求头,但校验是否存在可能需要使用断言。 突然想到,在路由配置中,可以使用断言(Predicates)来匹配请求头,例如Header断言,这样只有当请求包含指定头时才会路由到对应的服务。如果没有匹配的路由,则会返回404。但用户可能希望返回更具体的响应,如400 Bad Request,而不仅仅是404。这时候可能需要结合断言和过滤器,或者使用自定义逻辑。 但是用户的问题是如何使用内置的GatewayFilterFactory来实现校验。如果内置的过滤器工厂中没有直接提供这样的功能,可能需要使用自定义过滤器。不过可能存在一种方法,比如使用过滤器来检查请求头,并在不存在时设置响应状态。 例如,可以使用ModifyResponseBody或SetStatus过滤器,但需要结合条件判断。或者,使用Script GatewayFilterFactory,通过编写脚本来检查请求头,但这可能比较复杂。 或者,使用AddResponseHeader过滤器在特定条件下添加响应头,但这可能不够。 可能用户的问题的答案是需要使用断言来确保请求头存在,否则路由不匹配,返回404。但用户可能希望更主动地校验,并返回自定义的错误响应。这时可能需要自定义过滤器,但问题强调使用内置的GatewayFilterFactory,所以可能答案是需要结合断言和过滤器,或者指出没有直接的内置过滤器,但可以通过配置路由的断言来实现基本校验,或者使用自定义过滤器。 不过,可能我遗漏了某个内置的过滤器工厂。例如,Spring Cloud Gateway有一个名为CheckAuth的过滤器,但可能不是内置的。或者,可能需要使用CircuitBreaker过滤器,但这不相关。 再查资料,发现有一个名为SecureHeaders的过滤器工厂,但这是添加安全头的。另一个可能是使用RequestHeaderSize过滤器,但这检查头的大小而不是存在性。 综上,可能没有直接的内置GatewayFilterFactory来校验请求头是否存在,但可以通过路由的断言(Header断言)来实现,当请求头不存在时,该路由不会被匹配,可以返回404。或者,如果需要返回其他状态码,可能需要自定义过滤器。或者,使用某个内置的过滤器结合条件判断,比如使用RemoveRequestHeader过滤器,但需要条件判断是否存在。 不过,用户的问题明确要求使用内置的GatewayFilterFactory,所以可能的结论是:没有直接的内置过滤器来实现此功能,但可以通过配置路由的断言来间接实现校验,或者需要使用自定义过滤器。不过,可能我记错了,是否存在某个过滤器工厂可以直接实现? 另外,可能可以使用RewritePath或RedirectTo结合某些条件,但不太直接。 或者,使用AddRequestHeaderIfAbsent,但这可能不适用于校验,而是添加头。 可能正确的回答是:Spring Cloud Gateway没有直接的内置GatewayFilterFactory来校验请求头是否存在,但可以通过配置路由的断言(如Header断言)来确保只有携带特定请求头的请求才会被路由。如果请求头不存在,该路由将不匹配,返回404。如果需要返回更具体的状态码,可以结合自定义的过滤器或者错误处理。 不过,用户可能希望更直接的解决方案,比如在过滤器链中检查请求头并返回错误。这时候需要使用自定义过滤器,但用户问题明确询问内置的GatewayFilterFactory,因此需要明确说明是否有内置的支持。 经过仔细回忆,可能Spring Cloud Gateway的内置过滤器中并没有直接提供校验请求头是否存在的过滤器工厂,因此答案是需要通过断言或者自定义过滤器来实现。但需要确认这一点。 或者,是否有其他方式,例如使用ModifyRequestBody过滤器,结合SpEL表达式来检查请求头,但可能不太适用。 最后,正确的步骤应该是: 1. 使用路由配置中的Header断言来确保请求必须包含特定头。 2. 如果断言不满足,路由不匹配,返回404。 3. 如果需要自定义响应,可以配置默认的路由或全局过滤器来处理这种情况。 因此,在回答中应该说明如何通过Header断言来实现校验,并指出如果需要更复杂的处理(如返回400),则需要自定义过滤器。</think>以下是如何使用Spring Cloud Gateway内置机制校验请求头是否存在的分步说明: $$注意:Spring Cloud Gateway没有直接校验请求头的内置过滤器工厂,但可通过路由断言实现基础校验$$ ### 一、通过`Header`路由断言实现校验 在路由配置中添加断言(Predicate),仅当请求包含指定头时才匹配路由: ```yaml spring: cloud: gateway: routes: - id: header_validation_route uri: http://backend-service predicates: - Header=X-Required-Header, \d+ # 校验是否存在且值匹配正则表达式 filters: - AddRequestHeader=X-Status, Valid ``` #### 效果说明: 1. 当请求**携带**`X-Required-Header`头且值符合正则时: - 路由匹配成功,请求转发至后端服务 - 自动添加`X-Status: Valid`头 2. 当请求**未携带**该头或值不匹配时: - 返回`404 Not Found`(默认行为) --- ### 二、进阶处理(自定义响应) 若需要返回`400 Bad Request`等自定义响应,需结合自定义过滤器: #### 1. 创建全局过滤器 ```java @Component public class HeaderValidationFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { if (!exchange.getRequest().getHeaders().containsKey("X-Required-Header")) { exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } } ``` #### 2. 配置生效范围 通过`@Order`注解控制过滤器执行顺序,或使用`routes`配置局部过滤器: ```yaml routes: - id: custom_filter_route uri: http://backend-service filters: - name: HeaderValidationFilter # 注册为Bean后可直接引用 ``` --- ### 三、方案对比 | 方案 | 优点 | 缺点 | |--------------------|------------------------------|------------------------------| | Header路由断言 | 配置简单,无代码侵入 | 仅返回404,无法自定义响应 | | 自定义全局过滤器 | 完全控制响应逻辑 | 需要编写Java代码 | --- ### 最佳实践建议 1. **简单校验**:优先使用`Header`断言 2. **复杂逻辑**:通过`GlobalFilter`实现自定义校验 3. **响应标准化**:结合`ErrorWebExceptionHandler`统一处理错误格式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值