Spring-Cloud-Gateway实现自定义过滤器

本文介绍了如何在Spring Cloud Gateway中实现自定义过滤器,包括全局过滤器和局部过滤器。全局过滤器对所有路由生效,而局部过滤器仅对指定路由生效。通过实现GlobalFilter和Ordered接口并设置getOrder方法来控制过滤器执行顺序。文中展示了过滤器执行流程,并给出了A、B、C和MyAuth四个全局过滤器的示例,其中MyAuthFilter用于权限验证。此外,还讲解了局部过滤器的创建步骤,并提供了一个用于检查请求头user-id的局部过滤器示例。

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

Spring-Cloud-Gateway实现自定义过滤器


本篇博客主要搬运自开课吧提供的课堂笔记,目的是方便自身复习查找,如有不当之处,请联系博主

过滤器执行次序

Spring-Cloud-Gateway 基于过滤器实现,同 zuul 类似,有pre和post两种方式的 filter,分别处理前置逻辑和后置逻辑。客户端的请求先经过pre类型的 filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过post类型的 filter 处理,最后返回响应到客户端。
过滤器执行流程如下,order 越大,优先级越低,如图所示。
在这里插入图片描述
过滤器分为全局过滤器和局部过滤器。

  • 全局过滤器:对所有路由生效
  • 局部过滤器:对指定的路由生效

全局过滤器

实现 GlobalFilter 和 Ordered,重写相关方法,加入到spring容器管理即可,无需配置,全局过滤器对所有的路由都有效。代码如下。

@Configuration
public class FilterConfig
{

    @Bean
    public GlobalFilter a()
    {
        return new AFilter();
    }

    @Bean
    public GlobalFilter b()
    {
        return new BFilter();
    }

    @Bean
    public GlobalFilter c()
    {
        return new CFilter();
    }

    @Bean
    public GlobalFilter myAuthFilter()
    {
        return new MyAuthFilter();
    }


    @Slf4j
    static class AFilter implements GlobalFilter, Ordered
    {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("AFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("AFilter后置逻辑");
            }));
        }

        //   值越小,优先级越高
        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 100;
        }
    }

    @Slf4j
    static class BFilter implements GlobalFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("BFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("BFilter后置逻辑");
            }));
        }

        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 200;
        }
    }

    @Slf4j
    static class CFilter implements GlobalFilter, Ordered
    {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("CFilter前置逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("CFilter后置逻辑");
            }));
        }

        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 300;
        }
    }


    @Slf4j
    static class MyAuthFilter implements GlobalFilter, Ordered {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("MyAuthFilter权限过滤器");
            String token = exchange.getRequest().getHeaders().getFirst("token");
            if (StringUtils.isBlank(token)) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            return chain.filter(exchange);
        }

        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE + 400;
        }
    }


}

配置文件如下:

  cloud:
    gateway:
      routes:
        - id: url-proxy-2
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/**

定义了4个全局过滤器,顺序为A>B>C>MyAuthFilter,其中全局过滤器MyAuthFilter中判断令牌是否存在,如果令牌不存在,则返回401状态码,表示没有权限访问,使用Postman执行请求,如图所示。
在这里插入图片描述
如果码掉过滤器MyAuthFilter,则可以在控制台中看出order大小对过滤器执行顺序的影响。
在这里插入图片描述

局部过滤器

定义局部过滤器步骤如下。

  • 需要实现GatewayFilter, Ordered,实现相关的方法
  • 包装GatewayFilter,产生GatewayFilterFactory
  • GatewayFilterFactory加入到过滤器工厂,并且注册到spring容器中。
  • 在配置文件中进行配置,如果不配置则不启用此过滤器规则。

接下来定义局部过滤器,对于请求头user-id校验,如果不存在user-id请求头,直接返回状态码406。代码如下。

@Component
public class UserIdCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<Object>
{
    @Override
    public GatewayFilter apply(Object config)
    {
        return new UserIdCheckGateWayFilter();
    }

    @Slf4j
    static class UserIdCheckGateWayFilter implements GatewayFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            String url = exchange.getRequest().getPath().pathWithinApplication().value();
            log.info("请求URL:" + url);
            log.info("method:" + exchange.getRequest().getMethod());
            //获取header
            String userId = exchange.getRequest().getHeaders().getFirst("user-id");
            log.info("userId:" + userId);

            if (StringUtils.isBlank(userId))
            {
                log.info("*****头部验证不通过,请在头部输入  user-id");
                //终止请求,直接回应
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }

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


}

配置文件application.yml代码如下。

spring:
  cloud:
    gateway:
      routes:        
        - id: service14
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/{segment}
      default-filters:
        - PrefixPath=/payment
        - UserIdCheck
<think>嗯,用户想深入了解Spring Cloud Gateway的内部工作原理和实现机制。从用户之前的提问来看,ta应该是个有经验的Java开发者,正在研究微服务架构中的网关技术。用户可能正在搭建或优化微服务架构,需要理解网关的核心机制来做出技术决策或解决实际问题。 用户提供的引用材料很丰富,主要涉及Spring Cloud Gateway的定位(替代Zuul)、核心依赖(WebFlux)、服务发现集成(Nacos、Kubernetes)和配置方式。不过用户明确要求的是"原理及工作机制",所以需要聚焦在架构设计层面而非配置细节。 首先需要解释清楚反应式编程模型这个基础,因为这是理解整个网关工作流的钥匙。WebFlux的非阻塞特性决定了网关的线程模型和请求处理方式,这点必须优先说明。然后要突出过滤器链这个核心设计模式,用户可能熟悉Servlet Filter,但反应式过滤器的差异需要特别强调。 路由机制部分需要区分配置阶段和运行时阶段:配置阶段强调Predicate和Filter的声明式特性,运行时阶段则要说明路由定位的流程。负载均衡作为高频使用功能,需要点明其通过ReactorLoadBalancer的集成位置。 用户可能还会关心实际性能表现,所以补充了工作流示例和性能优化点。最后的扩展机制说明是为了让用户知道如何定制网关,毕竟实际项目总会需要自定义Filter。 相关问题设计成阶梯式:从核心原理(WebFlux)到具体组件(Predicate),再到优化实践,最后是监控集成。这样用户可以根据当前需要选择深入方向。特别加入"与Zuul对比"的问题,因为引用[2]提到它是Zuul替代品,这个点开发者通常很关注。 需要避免陷入具体配置的讲解,比如引用[4]中的YAML示例就不展开,保持讨论在架构层面。但负载均衡的"lb://"语法值得提及,因为它是路由配置的关键符号。</think>Spring Cloud Gateway 的核心工作原理基于 **响应式编程模型(Spring WebFlux)** 和 **过滤器链(Filter Chain)** 设计,其工作机制可分解如下: --- ### 一、核心架构 1. **基于 WebFlux 的响应式引擎** Gateway 底层使用 **Project Reactor** 和 **Netty** 实现非阻塞 I/O,通过 `Reactor Netty` 处理 HTTP 请求,支持高并发场景[^1][^2]。 2. **路由(Route)核心组件** - **Predicate(断言)**:匹配请求的条件(如 Path、Header、Method 等),决定是否路由到目标 URI。 - **Filter(过滤器)**:处理请求和响应的逻辑单元(如添加 Header、重写路径、限流等)。 - **URI**:目标服务地址,支持 `lb://`(负载均衡)或 `http://`(直连)协议[^4]。 ```yaml spring: cloud: gateway: routes: - id: user_route uri: lb://user-service # 负载均衡到 user-service predicates: - Path=/api/users/** # 匹配路径 filters: - AddRequestHeader=X-Gateway, true # 添加请求头 ``` --- ### 二、请求处理流程 1. **路由匹配** 客户端请求 → Gateway 根据 `Predicate` 匹配路由规则 → 定位到目标 URI(如 `lb://service-name`)。 2. **过滤器链执行** 请求依次通过 **Gateway Filter** 链(Pre-Filters)→ 转发到目标服务 → 响应返回时通过 **Post-Filters** 处理[^1]。 ```mermaid graph LR A[客户端请求] --> B[Pre-Filters] B --> C{转发到目标服务} C --> D[目标服务处理] D --> E[Post-Filters] E --> F[返回响应] ``` 3. **负载均衡(Load Balancing)** 若 URI 为 `lb://service-name`,通过 **Spring Cloud LoadBalancer** 从注册中心(如 Nacos、Eureka)获取实例列表,按策略(轮询、随机等)选择实例[^3][^4]。 --- ### 三、关键机制详解 1. **过滤器类型** - **GatewayFilter**:作用于单个路由(如限流、重试)。 - **GlobalFilter**:全局生效(如认证、日志),通过 `@Order` 控制执行顺序。 ```java @Bean @Order(-1) public GlobalFilter authFilter() { return (exchange, chain) -> { // 身份验证逻辑 return chain.filter(exchange); }; } ``` 2. **动态路由** 支持通过 **Spring Cloud Config** 或 **Nacos 配置中心** 实时更新路由规则,无需重启网关。 3. **服务发现集成** 依赖 `spring-cloud-starter-kubernetes-discovery` 或 `spring-cloud-starter-alibaba-nacos-discovery`,自动同步注册中心的服务列表[^3][^4]。 --- ### 四、性能优化点 1. **使用缓存**:缓存路由定义,避免每次请求解析配置。 2. **精简 Filter 链**:减少非必要 Filter 的执行耗时。 3. **响应式编程优化**:避免在 Filter 中阻塞线程(如使用 `Mono.defer()` 处理异步操作)。 --- ### 五、扩展机制 1. **自定义 Predicate**:实现 `RoutePredicateFactory` 接口扩展匹配条件。 2. **自定义 Filter**:继承 `AbstractGatewayFilterFactory` 实现业务逻辑。 3. **集成 Sentinel**:通过 `spring-cloud-alibaba-sentinel-gateway` 实现熔断降级。 --- ### 工作流示例 ```mermaid sequenceDiagram Client->>+Gateway: HTTP 请求 /api/users Gateway->>Gateway: 匹配 Predicate (Path=/api/users/**) Gateway->>Gateway: 执行 Pre-Filters (认证、限流) Gateway->>LoadBalancer: 获取 user-service 实例 LoadBalancer-->>Gateway: 返回实例地址 (192.168.1.10:8080) Gateway->>user-service: 转发请求 user-service-->>Gateway: 返回响应 Gateway->>Gateway: 执行 Post-Filters (日志、修改响应头) Gateway-->>-Client: 返回最终响应 ``` --- **相关问题** 1. Spring WebFlux 的响应式模型如何提升 Gateway 的并发性能? 2. Gateway 的 GlobalFilter 与 Zuul 的 Filter 有何本质区别? 3. 如何实现动态路由更新而不重启网关服务? 4. Gateway 集成 Spring Cloud LoadBalancer 时如何自定义负载均衡策略? 5. 如何通过 Gateway 的 Filter 实现全链路灰度发布? 6. Gateway 与 Nacos 的服务发现集成机制是怎样的? 7. 如何监控 Gateway 的请求延迟和错误率? [^1]: Spring-cloud-gateway 源码浅析,基于 WebFlux 和 Filter Chain 架构。 [^2]: Spring-Cloud-Gateway 作为 Zuul 的替代方案,采用非阻塞式设计。 [^3]: 依赖 `spring-cloud-kubernetes-discovery` 实现 Kubernetes 服务发现。 [^4]: 通过 `lb://` 协议和 Nacos 实现负载均衡路由。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值