如何在 Spring Cloud Gateway 中创建全局过滤器、局部过滤器和自定义条件过滤器

Spring Cloud Gateway 是一个功能强大的 API 网关,能够处理 HTTP 请求、响应及路由。通过过滤器机制,您可以在请求和响应过程中进行各种处理操作,如记录日志、身份验证、限流等。Spring Cloud Gateway 提供了三种主要类型的过滤器:全局过滤器局部过滤器自定义条件过滤器。本文将详细介绍如何在 Spring Cloud Gateway 中创建和使用这些过滤器。

1. 全局过滤器(Global Filter)

全局过滤器是应用于所有请求的过滤器,无论请求被路由到哪个目标服务,都会先经过这些过滤器。全局过滤器适用于需要对所有请求进行操作的场景,如日志记录、请求限流、身份验证等。

创建全局过滤器的步骤

步骤 1:实现 GlobalFilter 接口

要创建全局过滤器,您需要实现 GlobalFilter 接口,并重写 filter 方法。以下是一个简单的全局过滤器,它记录请求的开始时间,并在请求完成后输出请求的处理时长。

示例代码:全局过滤器
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import reactor.core.publisher.Mono;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        exchange.getAttributes().put("startTime", startTime);

        // 继续执行后续过滤器
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // 计算并输出请求时长
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            log.info("Request completed in " + duration + "ms");
        }));
    }
}
步骤 2:设置过滤器的执行顺序(可选)

GlobalFilter 接口继承自 Ordered 接口,您可以通过 getOrder() 方法设置过滤器的执行顺序。返回值越小,优先级越高。

@Override
public int getOrder() {
    return -1;  // 高优先级
}
步骤 3:配置全局过滤器

使用 @Component 注解注册全局过滤器,Spring 会自动将其作为全局过滤器进行管理。


2. 局部过滤器(Local Filter)

局部过滤器是应用于特定路由或请求路径的过滤器。它仅在匹配特定路由或条件时执行,适用于只对某些服务、路径或请求类型进行处理的场景。

创建局部过滤器的步骤

步骤 1:实现 GatewayFilter 接口

局部过滤器需要实现 GatewayFilter 接口。以下是一个简单的局部过滤器,它检查请求的路径并在符合条件时记录日志。

示例代码:局部过滤器
import org.springframework.stereotype.Component;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MyLocalFilter implements GatewayFilter {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求路径
        String path = exchange.getRequest().getURI().getPath();
        log.info("Request path: " + path);

        // 继续执行后续过滤器
        return chain.filter(exchange);
    }
}
步骤 2:通过 RouteLocator 配置路由

在 Spring Cloud Gateway 中,您可以通过 RouteLocator 或 YAML 配置文件为特定的路由添加局部过滤器。

示例代码:配置局部过滤器
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.RouteLocatorBuilder;

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("my_route", r -> r
                        .path("/api/**")  // 匹配 /api/** 路径的请求
                        .filters(f -> f.filter(new MyLocalFilter()))  // 应用 MyLocalFilter
                        .uri("http://example.com"))  // 目标服务
                .build();
    }
}

在这个例子中,我们创建了一个名为 my_route 的路由,它只对 /api/** 路径的请求应用 MyLocalFilter 过滤器。

方法二:基于 YAML 配置

如果你使用 YAML 配置文件来配置路由,也可以在 application.yml 文件中指定过滤器。

spring:
  cloud:
    gateway:
      routes:
        - id: example_route
          uri: http://example.com
          predicates:
            - Path=/api/v1/**
          filters:
            - name: MyLocalFilter  # 使用你定义的过滤器

为了通过 YAML 使用自定义过滤器,你需要确保在配置中通过 Spring Bean 名称引用该过滤器。若 MyLocalFilter 被 Spring 管理(通过 @Component),可以直接使用 name 来引用。


3. 自定义条件过滤器(Custom Condition Filter)

自定义条件过滤器是根据特定的条件(如请求的查询参数、请求头或路径等)来动态决定是否执行过滤器。这种过滤器提供了更高的灵活性和复杂的过滤逻辑。

创建自定义条件过滤器的步骤

步骤 1:继承 AbstractGatewayFilterFactory 创建过滤器工厂

Spring Cloud Gateway 提供了 AbstractGatewayFilterFactory 类,允许您创建自定义的过滤器工厂。您可以在工厂中设置过滤器的配置项,并根据条件来执行过滤逻辑。

示例代码:自定义条件过滤器
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerHttpRequest;
import org.springframework.http.HttpStatus;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory {

    public MyGatewayFilterFactory() {
        super(MyGatewayFilterFactory.Config.class); // 指定配置类
    }

    @Override
    public GatewayFilter apply(MyGatewayFilterFactory.Config config) {
        // 创建实际的过滤器
        return new GatewayFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                System.out.println("进入了自定义网关过滤器,status:" + config.getStatus());

                // 检查请求的查询参数
                if (request.getQueryParams().containsKey("atguigu")) {
                    return chain.filter(exchange);  // 继续请求
                } else {
                    exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);  // 返回 400 错误
                    return exchange.getResponse().setComplete();  // 完成响应
                }
            }
        };
    }

    // 配置快捷字段的顺序
    @Override
    public List shortcutFieldOrder() {
        return Arrays.asList("status");  // 配置字段名
    }

    // 配置类,保存过滤器的参数
    public static class Config {
        private String status;  // 配置字段

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }
    }
}
步骤 2:在配置文件中应用自定义过滤器

您可以通过 YAML 或 Java 配置文件指定在哪些路由上应用此自定义条件过滤器,并传递参数。

示例代码:在 application.yml 中配置自定义过滤器
spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://example.com
          predicates:
            - Path=/api/**  # 匹配 /api/** 路径的请求
          filters:
            - name: MyGatewayFilterFactory  # 引用自定义的过滤器
              args:
                status: "active"  # 配置 status 参数

4. 过滤器类型比较

特性 全局过滤器 (Global Filter) 局部过滤器 (Local Filter) 自定义条件过滤器 (Custom Condition Filter)
适用范围 所有请求 特定路由或路径的请求 基于特定条件,如请求参数、路径等,动态判断是否执行
使用场景 日志记录、全局认证、全局限流等 特定服务或路径的处理 根据条件(如请求参数、头部等)动态处理请求
配置方式 通过实现 GlobalFilter 接口并注册为 Spring Bean 通过 RouteLocator 或 YAML 配置路由 通过 AbstractGatewayFilterFactory 创建工厂

5. 总结

在 Spring Cloud Gateway 中,您可以根据不同的需求创建三种类型的过滤器:

  • 全局过滤器:适用于需要对所有请求进行统一处理的场

景,例如日志记录、认证和授权。

  • 局部过滤器:适用于特定路由或路径的请求,能够灵活地控制不同服务的请求处理。
  • 自定义条件过滤器:根据请求的特定条件(如查询参数、请求头、路径等)动态决定是否执行过滤器逻辑,提供更高的灵活性。

你可能感兴趣的:(java,spring,boot,spring)