一、核心概念

1. 全局过滤器(GlobalFilter)

  • 定义:对所有请求生效的过滤器,无论请求路由到哪个服务。
  • 应用场景
    • 统一鉴权:校验 Token 或 Session。
    • 日志记录:记录请求的耗时、IP、路径等。
    • 限流:对高频接口进行流量控制。
    • 参数校验:校验请求头或查询参数。

2. 局部过滤器(GatewayFilter)

  • 定义:仅对特定路由生效的过滤器,用于细粒度控制。
  • 应用场景
    • 路径重写RewritePath 过滤器修改请求路径。
    • 负载均衡:结合 LoadBalancerClientFilter 实现服务发现。

3. 过滤器执行顺序

  • 优先级规则
    • 前置阶段(pre):优先级高的过滤器先执行。
    • 后置阶段(post):优先级高的过滤器后执行。
    • 默认顺序GlobalFiltergetOrder() 返回值越小,优先级越高。

二、操作步骤(详细版)

1. 引入依赖

pom.xml 中添加以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2. 创建全局过滤器

(1)实现 GlobalFilter 接口

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 前置处理逻辑
        System.out.println("请求开始: " + exchange.getRequest().getPath());

        // 继续执行后续过滤器
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // 后置处理逻辑(响应发送后执行)
            System.out.println("请求结束");
        }));
    }

    @Override
    public int getOrder() {
        return 0; // 数值越小优先级越高
    }
}

(2)配置过滤器顺序

  • 方式一:通过 @Order 注解
    @Component
    @Order(1)
    public class AuthFilter implements GlobalFilter, Ordered { ... }
    
  • 方式二:在 application.yml 中配置
    spring:
      cloud:
        gateway:
          default-filters:
            - name: MyGlobalFilter
              args:
                order: 0
    

3. 测试全局过滤器

(1)启动网关服务

确保网关服务已启动,并配置了至少一个路由规则:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: http://localhost:8081
          predicates:
            - Path=/user/**

(2)发送请求

访问任意路由路径(如 http://localhost:8080/user/1),观察控制台输出:

请求开始: /user/1
请求结束

4. 动态调整过滤器

(1)通过 Nacos 配置中心动态更新

  1. 添加 Nacos 依赖:
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    
  2. 在 Nacos 配置文件中定义过滤器规则:
    spring:
      cloud:
        gateway:
          globalfilters:
            - name: MyGlobalFilter
              args:
                order: 0
    

三、常见错误及解决方案

1. 过滤器未生效

  • 原因
    • 未正确实现 GlobalFilter 接口。
    • 未通过 @Component 注解注册。
  • 解决方案
    • 检查类是否实现 GlobalFilterOrdered 接口。
    • 确保类被 Spring 扫描(如包路径一致)。

2. 过滤器顺序异常

  • 原因
    • getOrder() 返回值未正确设置。
    • 未区分 prepost 阶段。
  • 解决方案
    • 通过 getOrder() 明确优先级。
    • 使用 OrderedGatewayFilter 显式指定阶段。

3. 阻塞线程导致性能下降

  • 原因
    • filter 方法中执行同步阻塞操作(如数据库查询)。
  • 解决方案
    • 使用异步处理(如 Mono.fromRunnable())。
    • 将耗时操作提交到线程池。

四、注意事项

  1. 避免阻塞操作

    • 使用 WebFlux 的非阻塞模型,避免在 filter 中直接调用 thread.sleep()
    • 耗时操作应异步化(如日志写入、外部 API 调用)。
  2. 合理设置优先级

    • 鉴权过滤器应设置较高优先级(如 order=-1),确保在路由前校验。
    • 日志过滤器可设置较低优先级(如 order=1000),在响应后记录。
  3. 异常处理

    • 使用 Mono.error() 抛出异常,确保网关返回统一错误码。
    • 避免直接抛出 RuntimeException,防止异常未捕获。

五、使用技巧

1. 日志记录优化

  • 示例:记录请求耗时
    public class LoggingFilter implements GlobalFilter, Ordered {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            long startTime = System.currentTimeMillis();
            exchange.getAttributes().put("startTime", startTime);
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                long duration = System.currentTimeMillis() - startTime;
                System.out.println("请求耗时: " + duration + "ms");
            }));
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

2. 参数传递与共享

  • 示例:在过滤器间传递数据
    exchange.getAttributes().put("userId", "123");
    String userId = exchange.getAttribute("userId");
    

3. 条件判断过滤

  • 示例:根据请求头动态跳过过滤
    if (exchange.getRequest().getHeaders().containsKey("Skip-Auth")) {
        return chain.filter(exchange);
    }
    

六、最佳实践

1. 统一鉴权

  • 场景:所有请求需携带 Token。
  • 策略
    • 实现 AuthFilter,校验请求头中的 Authorization 字段。
    • 若未通过校验,返回 401 Unauthorized

2. 限流与熔断

  • 场景:防止高频请求击穿后端服务。
  • 策略
    • 结合 Sentinel 或 Resilience4j 实现限流。
    • 在全局过滤器中调用限流规则。

3. 日志聚合与监控

  • 场景:集中记录请求日志,便于排查问题。
  • 策略
    • 使用 LogbackELK 实现日志收集。
    • 记录关键字段(如 IPPathStatus)。

七、性能优化

  1. 减少阻塞操作

    • 将数据库查询、外部 API 调用异步化。
    • 使用 ReactorpublishOn 指定线程池。
  2. 缓存频繁校验数据

    • 对 Token、用户权限等高频校验数据使用本地缓存(如 Caffeine)。
  3. 优化过滤器链

    • 合并多个过滤器逻辑,减少链路长度。
    • 避免在过滤器中执行复杂计算。
  4. 动态规则管理

    • 通过 Nacos 或 Apollo 动态更新过滤器规则,无需重启服务。

八、总结

Spring Cloud Gateway 的全局过滤器是实现统一请求处理的核心工具。通过合理设计过滤器逻辑、优化执行顺序、避免阻塞操作,可以有效提升网关的稳定性和性能。实际开发中,建议结合业务需求选择合适的过滤器策略,并通过日志与监控持续优化过滤器链。