Spring Cloud Gateway 中的自定义过滤器

在 Spring Cloud Gateway 中,过滤器是用于对请求和响应进行预处理和后处理的组件。通过自定义过滤器,您可以控制请求的生命周期,做如日志记录、身份认证、限流、重试、请求改写等操作。Spring Cloud Gateway 允许您创建 Global Filters(全局过滤器)和 Gateway Filters(局部过滤器),它们可以在不同的场景下提供灵活的定制。

下面我们将深入介绍如何在 Spring Cloud Gateway 中实现自定义过滤器。


1. 过滤器的种类

Spring Cloud Gateway 提供了三种类型的过滤器:

  1. Global Filters(全局过滤器):对所有路由生效的过滤器。常用于全局性的跨路由处理。
  2. Gateway Filters(局部过滤器):仅对特定路由生效的过滤器。
  3. Pre and Post Filters(前置和后置过滤器):
    • Pre Filters:请求到达路由之前执行,适用于身份验证、日志记录等。
    • Post Filters:请求到达路由后,返回响应之前执行,适用于响应修改、日志记录等。

2. 创建自定义过滤器

2.1 创建一个简单的 GatewayFilter

我们首先来创建一个简单的局部过滤器,它会记录每个请求的路径。

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.web.server.ServerWebExchange;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {

    // 定义配置类
    public static class Config {
        // 可定义配置参数
        private String prefix;

        public String getPrefix() {
            return prefix;
        }

        public void setPrefix(String prefix) {
            this.prefix = prefix;
        }
    }

    // 构造器
    public CustomGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // 返回一个自定义的过滤器
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                String path = exchange.getRequest().getURI().getPath();
                System.out.println("Request path: " + config.getPrefix() + path);
                return chain.filter(exchange); // 放行请求
            }
        };
    }
}

解释

  • CustomGatewayFilterFactory 继承了 AbstractGatewayFilterFactory,并实现了 apply() 方法,返回一个具体的过滤器。
  • 配置类 Config 可以用来传递配置参数,如添加请求路径的前缀。
  • filter() 方法中的 ServerWebExchange 可以获取请求的详细信息, GatewayFilterChain 用于继续链式处理请求。

2.2 注册自定义过滤器

自定义过滤器需要注册到 Spring Boot 上,以便在配置文件中应用。您可以通过 @Component 注解自动注册,也可以通过手动配置方式注册。

通过 @Component 自动注册:

  • 直接使用 @Component 注解使得过滤器在 Spring 容器中注册,Spring Boot 会自动扫描和创建实例。

通过手动注册:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;

@Configuration
public class GatewayFilterConfig {

    @Bean
    public GatewayFilterFactory customGatewayFilterFactory() {
        return new CustomGatewayFilterFactory();
    }
}

3. 配置过滤器应用于路由

一旦我们创建了自定义的过滤器,就可以在 application.yml 配置文件中将其应用到特定的路由。

spring:
  cloud:
    gateway:
      routes:
        - id: custom_route
          uri: http://httpbin.org:80
          predicates:
            - Path=/get
          filters:
            - name: CustomGatewayFilterFactory
              args:
                prefix: "Request path: "

解释

  • name: CustomGatewayFilterFactory 表示使用我们自定义的过滤器。
  • args 部分传递了配置参数(例如,prefix)到过滤器。

4. 全局过滤器的实现

全局过滤器是对所有路由生效的,可以通过实现 GlobalFilter 接口来创建全局过滤器。

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

@Component
public class CustomGlobalFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        System.out.println("Global filter: Request path: " + path);
        return chain.filter(exchange); // 放行请求
    }
}

解释

  • 实现 GlobalFilter 接口并覆盖 filter() 方法。
  • 这个过滤器会在每次请求进入网关时执行,适用于全局场景。

5. 高级过滤器:认证与权限控制

在实际项目中,过滤器常常用于实现认证与权限控制。比如我们可以在 pre 过滤器中检查请求的 Authorization 头信息,并判断用户是否有权限访问该路由。

@Component
public class AuthenticationFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        
        if (token == null || !isValidToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete(); // 返回 401 状态码
        }

        return chain.filter(exchange); // 验证成功,放行请求
    }

    private boolean isValidToken(String token) {
        // 这里实现具体的 token 校验逻辑
        return token.equals("valid_token");
    }
}

解释

  • AuthenticationFilter 会在每个请求中检查是否存在 Authorization 头。
  • 如果没有 token 或者 token 无效,则返回 401 Unauthorized 状态码。

6. 过滤器的执行顺序

  • 前置过滤器GatewayFilter 的前置过滤器会在请求到达目标服务之前执行,可以用来修改请求、验证身份、日志记录等。
  • 后置过滤器PostFilter 会在目标服务响应后执行,可以用来修改响应、日志记录、性能分析等。

Spring Cloud Gateway 提供了丰富的过滤器,可以在路由配置中灵活组合它们。

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://httpbin.org:80
          predicates:
            - Path=/get
          filters:
            - name: RequestTimeGatewayFilterFactory

7. 结论

在 Spring Cloud Gateway 中,过滤器为处理请求和响应提供了灵活的处理机制。通过自定义过滤器,您可以轻松实现认证、权限校验、日志记录、请求重定向等功能。具体应用时可以根据需要创建 全局过滤器 或 局部过滤器

在开发过程中,建议:

  • 使用 全局过滤器 处理与所有路由相关的操作,如认证、日志等。
  • 使用 局部过滤器 实现特定路由的功能,如请求路径修改、负载均衡等。

过滤器不仅提供了强大的功能扩展点,还能帮助优化性能、增强安全性和灵活性,充分发挥 Spring Cloud Gateway 的优势。