[Srping Cloud] Gateway:Predicate 路由匹配与全链路过滤器实战

Predicate

Predicate 是 Java8 提供的函数时编程接口 , 接收参数并返回一个 boolean 值 , 用于条件过过滤 , 请求参数的校验

定义一个Predicate

java 复制代码
/**
 * 判断字符串是否为空
 * 空  -true
 * 非空 -false
 */
public class StringPredicate implements Predicate<String> {
    @Override
    public boolean test(String s) {
        return s == null || s.isEmpty();
    }
}

在测试类中调用这个方法

① 常规用法

java 复制代码
@Test
public void test(){
    Predicate<String> predicate = new StringPredicate();
    System.out.println(predicate.test(""));
    System.out.println(predicate.test("aa"));
}

② 匿名内部类

java 复制代码
@Test
public void test2(){
    Predicate<String> predicate = new StringPredicate(){
        public boolean test(String s){
            return s.isEmpty();
        }
    };
    System.out.println(predicate.test(""));
    System.out.println(predicate.test("aa"));

}

③lambda 写法

java 复制代码
@Test
public void test3(){
    Predicate<String> predicate = s->s == null||s.isEmpty();
    System.out.println(predicate.test(""));
    System.out.println(predicate.test("aa"));
}

Route Predicate Factories(路由断言工厂)

在 Spring Cloud Gateway 中 , Predicate 提供了路由规则的匹配机制

在配置文件中 写的断言规则只是字符串 , 这些字符串会被 Route Predicate Factories 读取并处理 , 转变为路由判断的条件

官网 : Route Predicate Factories :: Spring Cloud Gateway

结合官网提供以下示例 :

|------------|-----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| After | 匹配指定日期时间之后的请求。需要一个 Java ZonedDateTime 对象作为参数。 | predicates: - After=2017-01-20T17:42:47.789-07:00America/Denver |
| Before | 匹配指定日期时间之前的请求。需要一个 Java ZonedDateTime 对象作为参数。 | predicates: - Before=2017-01-20T17:42:47.789-07:00America/Denver |
| Between | 匹配两个指定日期时间之间的请求。需要两个 Java ZonedDateTime 对象作为参数,第二个参数必须在第一个参数之后。 | predicates: - Between=2017-01-20T17:42:47.789-07:00America/Denver, 2017-01-21T17:42:47.789-07:00America/Denver |
| Cookie | 匹配请求中包含指定 Cookie 名称,且其值符合指定正则表达式的请求。参数格式为:name, regexp。 | predicates: - Cookie=chocolate, ch.p |
| Header | 匹配请求中包含指定 Header 名称,且其值符合指定正则表达式的请求。参数格式为:name, regexp。 | predicates: - Header=X-Request-Id, \d+ |
| Host | 匹配请求的 Host 头字段符合指定模式。支持 Ant 风格的路径匹配(如 **)。多个模式用逗号分隔。 | predicates: - Host=**.somehost.org, **.anotherhost.org |
| Method | 匹配指定的 HTTP 请求方法(如 GET, POST, PUT 等)。多个方法用逗号分隔。 | predicates: - Method=GET, POST |
| Path | 匹配请求的 URL 路径符合指定模式。支持 Ant 风格的路径匹配和路径变量(如 {segment})。 | predicates: - Path=/red/{segment}/blue/{segment} |
| RemoteAddr | 匹配请求的远程 IP 地址在指定范围内。支持 CIDR 表示法(如 /24)。多个地址用逗号分隔。 | predicates: - RemoteAddr=192.168.1.1/24 |

Gateway Filter factories (网关过滤工厂)

Predicate 决定了请求由哪一个路由处理 , 如果在请求处理前后需要加一些逻辑 , 这需要 Filter (过滤器)

按执行时机分为两种类型 : Pre 和 Post 类型

  • Pre 类型过滤器 : 路由处理之前执行 (请求转发到后端服务之前执行) , Pre 类型过滤器中可以做鉴权 , 限流等
  • Post 类型过滤器 : 请求执行完成后执行 (将结果返回给客户端之前执行)

按作用范围分为 : GatewayFilter 和 GlobalFilter

  • GatewayFilter : 应用到单个路由或者一个分组的路由上
  • GlobalFilter : 应用到所有到的路由上

GatewayFilter :

添加 gateway 的配置文件中添加 filter

此 filter 只在 order-service 下生效 , 效果是在所有的请求中加上参数 userName : bite

此处不做示范 , 需要修改大量代码

继续阅读官网 : AddRequestHeader GatewayFilter Factory :: Spring Cloud Gateway

此目录下包含大量 filter

GlobalFilter

GlobalFilter 是 Spring Cloud Gateway 中的全局过滤器 , 和 GatewayFilter 的作用几乎相同

参考官网 : Global Filters :: Spring Cloud Gateway

①gateway 的 pom 添加依赖
复制代码
<dependency> 
<groupId>org.springframework.bootgroupId> 
<artifactId>spring-boot-starter-actuatorartifactId> 
</dependency>
② gateway 的配置文件中添加配置
复制代码
spring:
  cloud:
    gateway:
      metrics:
        enabled: true

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always
    shutdown:
      enabled: true
  1. Spring Cloud Gateway 指标配置
  • 作用:开启 Spring Cloud Gateway 的网关指标收集功能
  • 详细说明 :当设置为 true 时,网关会收集一系列与运行相关的指标数据(如路由ID、转发URI、HTTP状态码、请求耗时等)。这些数据能够帮助开发者和运维人员更好地了解网关的运行状态、性能表现以及流量情况,且通常可方便地与 Prometheus 等工具集成以创建监控面板
  1. Actuator 端点暴露配置
  • 作用:控制哪些 Actuator 端点可以通过 HTTP 对外暴露访问
  • 详细说明include: "*" 表示暴露所有的 Actuator 监控端点(如 /health/info/metrics/env/beans 等)。默认情况下,出于安全考虑,Spring Boot 仅暴露 /health/info
  1. 健康检查详情配置
  • 作用 :控制访问 /actuator/health 端点时,是否展示各个组件的详细健康信息
  • 详细说明 :设置为 always 表示对所有访问者始终展示详细的健康报告(如数据库连接状态、Redis状态、磁盘空间使用率等)。该属性还支持 never(默认,仅显示 UP/DOWN 状态)和 when-authorized(仅向通过认证的用户展示详情)
  1. 远程关闭服务配置
  • 作用:开启 Actuator 的远程优雅关闭应用功能
  • 详细说明 :默认情况下该功能是禁用的(false)。当设置为 true 时,允许通过向 /actuator/shutdown 端点发送 POST 请求来远程关闭应用程序

测试http://127.0.0.1:10030/actuator 查看本地运行的 Spring Boot 应用程序的"健康状况总览面板"

过滤器执行的先后顺序

  • spring 提供的 filter 都有默认的 order 值 , order 值越小 , 越优先执行 ; 当 order 值相同时按defaultFilter > GatewayFilter > GlobalFilter执行
  • 可以通过自定义 filter 来指定 order ; Filter 通过实现 Order()接口或者添加@Order 注解来指定 order 值

自定义 filter

①GatewayFilter

CustomGatewayFilterFactory (必须以****GatewayFilterFactory 命名)

java 复制代码
package com.boop.gateway;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Slf4j
@Component
public class CustomGatewayFilterFactory
        extends AbstractGatewayFilterFactory<CustomConfig>
        implements Ordered {


    public CustomGatewayFilterFactory(){
        super(CustomConfig.class);
    }
    @Override
    public GatewayFilter apply(CustomConfig config) {
        /**
         * Mono<void> filter (ServerWebExchange exchange,GatewayFilterChain chain)
         * ServerWebExchange: http请求-响应交互的契约, 提供对http请求和响应的访问, 服务器端请求属性, 请求示例,响应示例等, 类似Context角色
         * GatewayFilterChain: 过滤器连
         * Mono: Reactor核心类, 数据流发布者, Mono最多只触发一个事件, 所以可以把Mono用于一步任务完成时发出的通知
         * Mono.fromRunnable: 创建一个包含Runnable元素的数据流
         */
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // [Pre] 前置处理逻辑
                log.info("[Pre] Filter Request, name:" + config.getName());

                // 继续执行过滤器链,并在链执行完毕后执行后置逻辑
                return chain.filter(exchange).then(Mono.fromRunnable(new Runnable() {
                    @Override
                    public void run() {
                        // [Post] 后置处理逻辑
                        log.info("[Post] Response Filter");
                    }
                }));
            }
        };
    }
//    public GatewayFilter apply(CustomConfig config) {
        /**
         * Mono<void> filter (ServerWebExchange exchange,GatewayFilterChain chain)
         * ServerWebExchange: http请求-响应交互的契约, 提供对http请求和响应的访问, 服务器端请求属性, 请求示例,响应示例等, 类似Context角色
         * GatewayFilterChain: 过滤器连
         * Mono: Reactor核心类, 数据流发布者, Mono最多只触发一个事件, 所以可以把Mono用于一步任务完成时发出的通知
         * Mono.fromRunnable: 创建一个包含Runnable元素的数据流
         */
//        return (((exchange, chain) -> {
//            log.info("[Pre] Filter Request, name:"+config.getName());
//            return chain.filter(exchange).then(Mono.fromRunnable(()->{
//                log.info("[Post] Response Filter");
//            }));
//        }));
//    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;//配置优先级,order越大,优先级越低
    }
}

注意 :

  1. 类名统一以 ****GatewayFilterFactory 命名 , 默认情况下 , 过滤器的 name 会采用该定义类的前缀 此处的 name = Custom
  2. apply 中 , 包含 Pre 和 Post 过滤 , then 方法中是请求执行结束之后处理的
  3. CustomConfig 是一个配置类 , 该类只有一个属性 name , 和 yml 的配置对应
  4. 需要 @Component 注解 , 交给 Spring 统一管理
  5. getOrger 表示该过滤器的优先级 , 值越大 , 优先级越高

CustomConfig

java 复制代码
@Data
public class CustomConfig {
    private String name;
}

gateway 的配置文件

html 复制代码
spring:
  cloud:
    gateway:
      routes: # 网关路由配置
        - id: product-service          # 路由ID,自定义,唯一即可
          uri: lb://product-service    # 目标服务地址
          predicates:                  # 路由条件
            - Path=/product/**
          filters:
            - name: Custom
              args:
                name: custom filter

测试 : http://127.0.0.1:10030/order/1

测试时最好测试多次请求 , 第一次启动服务会有初始化信息的日志

②GlobalFilter

实现方式比较简单 只需要实现GlobalFilter,Ordered 两个接口 , 就自动会过滤所有的 Filter

CustomGlobalFilter

java 复制代码
@Component
@Slf4j
public class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("Pre Global Filter");
        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            log.info("Post Global Filter...");
        }));
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

注意 : GlobalFilter 与 GatewayFilter 运行方式不同 , GlobalFilter 不需要遵守类名后缀的规则 , 只需要继承GlobalFilter, Ordered 并加上@Component 注解 就会被自动识别

测试 : http://127.0.0.1:10030/order/1

同上 : 测试时最好测试多次请求 , 第一次启动服务会有初始化信息的日志