Spring Cloud Gateway自定义过滤器

Spring Cloud Gateway:我的地盘我做主!😎 自定义过滤器,玩转流量的魔法棒!

各位观众,各位朋友,大家好!我是你们的老朋友,人称“代码界的段子手”的程序猿老王!今天,咱们不聊那些高大上的架构理论,也不谈那些深奥难懂的算法,咱们来点接地气的,聊聊Spring Cloud Gateway的自定义过滤器!

说到Spring Cloud Gateway,那可是微服务架构中不可或缺的流量守门员!它就像一个精明的保安,负责接收所有请求,然后根据规则将它们分发到不同的服务。但是,再精明的保安也需要个性化定制,才能更好地满足我们的需求。而自定义过滤器,就是我们用来定制这个保安的魔法棒!✨

一、 什么是自定义过滤器?🤔 别怕,没那么玄乎!

想象一下,你开了一家餐厅,门口站着一位服务员。这位服务员的任务是引导顾客入座、检查顾客是否衣冠整洁、统计客流量等等。

  • Spring Cloud Gateway 就像这家餐厅。
  • 过滤器 就像这位服务员。
  • 默认过滤器 就像餐厅标配的服务员,只能做一些基本的事情。
  • 自定义过滤器 就像你专门培训的,拥有特殊技能的服务员,可以做更多个性化的事情。

简单来说,自定义过滤器就是你在Spring Cloud Gateway中添加的,可以对请求和响应进行拦截和处理的组件。它可以让你在请求到达目标服务之前或之后,做一些你想要做的事情,比如:

  • 权限校验: 只有VIP客户才能进入专属包间!
  • 日志记录: 记录每一位顾客的喜好,方便以后提供更贴心的服务!
  • 流量控制: 防止餐厅爆满,影响顾客体验!
  • 请求头修改: 统一顾客的称谓,显得更专业!
  • 响应体修改: 给顾客送上一份小甜点,增加回头率!

总之,自定义过滤器就像一块橡皮泥,你想把它捏成什么形状,就捏成什么形状!只要你能想到,它就能做到!💪

二、 为什么要自定义过滤器?🤷‍♂️ 原生的不够用吗?

Spring Cloud Gateway自带了很多开箱即用的过滤器,比如AddRequestHeaderGatewayFilterFactoryRewritePathGatewayFilterFactory等等。它们可以满足一些基本的场景。

但是,世界上的需求千奇百怪,总有一些需求是原生过滤器无法满足的。比如:

  • 需要根据用户的IP地址进行限流: 原生过滤器只能根据请求路径进行限流。
  • 需要对请求体进行加密或解密: 原生过滤器只能对请求头进行修改。
  • 需要根据请求的来源进行路由: 原生过滤器只能根据请求路径进行路由。

这时候,就需要我们自己动手,定制专属的过滤器,才能更好地解决问题。就像餐厅的标配服务员只能做一些基本的服务,但你想要提供更个性化的服务,就必须自己培养专门的服务员!

三、 如何自定义过滤器?👨‍💻 磨刀不误砍柴工!

自定义过滤器主要有两种方式:

  1. 实现GatewayFilter接口: 这是最基本的方式,也是最灵活的方式。
  2. 继承AbstractGatewayFilterFactory类: 这种方式可以简化配置,更加方便。

咱们先来看看第一种方式:

1. 实现GatewayFilter接口

这种方式就像自己从零开始搭建一个房子,你需要自己设计图纸、准备材料、一步一步地建造。虽然比较麻烦,但是也最灵活,可以完全按照自己的想法来设计。

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

@Component
public class AuthFilter implements GatewayFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 获取请求头中的token
        String token = exchange.getRequest().getHeaders().getFirst("token");

        // 2. 校验token是否有效
        if (token == null || token.isEmpty() || !token.equals("my-secret-token")) {
            // 3. 如果token无效,则返回401 Unauthorized
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 4. 如果token有效,则放行
        return chain.filter(exchange);
    }
}

代码解释:

  • @Component:将该类标记为Spring组件,方便Spring管理。
  • GatewayFilter接口:该接口是所有自定义过滤器的父接口,必须实现filter方法。
  • filter方法:该方法是过滤器的核心逻辑,接收两个参数:
    • ServerWebExchange:包含了请求和响应的所有信息。
    • GatewayFilterChain:过滤器链,用于将请求传递给下一个过滤器。
  • exchange.getRequest().getHeaders().getFirst("token"):获取请求头中的token。
  • exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED):设置响应状态码为401 Unauthorized。
  • exchange.getResponse().setComplete():结束请求处理,返回响应。
  • chain.filter(exchange):将请求传递给下一个过滤器。

2. 继承AbstractGatewayFilterFactory

这种方式就像购买了一个毛坯房,只需要进行简单的装修,就可以入住。虽然不如自己搭建房子那么灵活,但是也更加方便快捷。

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

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

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

    public LogFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 1. 获取请求的URI
            String uri = exchange.getRequest().getURI().toString();

            // 2. 打印日志
            System.out.println("请求URI:" + uri + ",是否打印响应:" + config.isPrintResponse());

            // 3. 放行
            return chain.filter(exchange);
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("printResponse");
    }

    public static class Config {
        private boolean printResponse;

        public boolean isPrintResponse() {
            return printResponse;
        }

        public void setPrintResponse(boolean printResponse) {
            this.printResponse = printResponse;
        }
    }
}

代码解释:

  • AbstractGatewayFilterFactory<LogFilterFactory.Config>:继承该类,并指定配置类为LogFilterFactory.Config
  • Config类:用于定义过滤器的配置参数。
  • shortcutFieldOrder方法:用于指定配置参数的顺序,方便在配置文件中配置。
  • apply方法:该方法是过滤器的核心逻辑,接收一个Config对象作为参数。

四、 如何配置自定义过滤器?📝 别忘了激活它!

自定义过滤器写好之后,还需要在配置文件中进行配置,才能生效。配置方式有两种:

  1. application.ymlapplication.properties中配置: 这种方式比较简单,但是不够灵活。
  2. 通过Java代码配置: 这种方式比较灵活,可以动态地修改配置。

咱们先来看看第一种方式:

spring:
  cloud:
    gateway:
      routes:
        - id: my-route
          uri: http://example.com
          filters:
            - AuthFilter # 使用实现GatewayFilter接口的过滤器
            - LogFilter=true # 使用继承AbstractGatewayFilterFactory的过滤器,并配置参数

代码解释:

  • filters:用于配置过滤器列表。
  • AuthFilter:使用实现GatewayFilter接口的过滤器,直接写过滤器的名称即可。
  • LogFilter=true:使用继承AbstractGatewayFilterFactory的过滤器,需要写过滤器的名称,并配置参数。

再来看看第二种方式:

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder, AuthFilter authFilter, LogFilterFactory logFilterFactory) {
        return builder.routes()
                .route("my-route", r -> r.path("/api/**")
                        .filters(f -> f.filter(authFilter)
                                       .filter(logFilterFactory.apply(config -> config.setPrintResponse(true))))
                        .uri("http://example.com"))
                .build();
    }
}

代码解释:

  • @Configuration:将该类标记为Spring配置类。
  • @Bean:将customRouteLocator方法标记为Spring Bean。
  • RouteLocatorBuilder:用于构建路由。
  • r.path("/api/**"):指定请求路径为/api/**的请求,都路由到该路由。
  • f.filter(authFilter):使用AuthFilter过滤器。
  • f.filter(logFilterFactory.apply(config -> config.setPrintResponse(true))):使用LogFilterFactory过滤器,并配置printResponse参数为true
  • uri("http://example.com"):指定目标服务地址为http://example.com

五、 最佳实践和注意事项 ⚠️ 千万别踩坑!

  1. 过滤器顺序很重要: 过滤器链中的过滤器顺序决定了它们的执行顺序。一定要根据实际需求,合理安排过滤器的顺序。
  2. 避免过度设计: 不要为了追求完美,而过度设计过滤器。只需要满足当前的需求即可,避免引入不必要的复杂性。
  3. 测试是王道: 在发布之前,一定要进行充分的测试,确保过滤器能够正常工作。
  4. 监控和告警: 监控过滤器的性能和错误率,及时发现和解决问题。
  5. 性能优化: 尽量避免在过滤器中进行耗时的操作,比如IO操作、数据库查询等。

六、 总结 🎉 恭喜你,又掌握了一项新技能!

今天,咱们一起学习了Spring Cloud Gateway的自定义过滤器,了解了它的概念、作用、实现方式和配置方式。希望通过今天的学习,大家能够掌握这项技能,并在实际工作中灵活运用,打造更加强大和稳定的微服务架构!

记住,自定义过滤器就像你的专属魔法棒,只要你敢想,它就能帮你实现!💪

最后,送大家一句代码界的至理名言:

  • Bug虐我千百遍,我待Bug如初恋! ❤️

希望大家在未来的编程道路上,能够披荆斩棘,勇往直前,成为一名真正的代码大师!😎

附:常用过滤器示例(表格形式)

过滤器名称 功能描述 示例代码
AddRequestHeaderGatewayFilterFactory 添加请求头。 yaml spring: cloud: gateway: routes: - id: add-request-header uri: http://example.com filters: - AddRequestHeader=X-Request-Id, 123456
RewritePathGatewayFilterFactory 重写请求路径。 yaml spring: cloud: gateway: routes: - id: rewrite-path uri: http://example.com filters: - RewritePath=/api/(?<segment>.*), /${segment}
RequestRateLimiterGatewayFilterFactory 限制请求速率。 yaml spring: cloud: gateway: routes: - id: request-rate-limiter uri: http://example.com filters: - RequestRateLimiter=redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 redis-rate-limiter.requestedTokens: 1
自定义鉴权过滤器 (AuthFilter) 验证用户身份,只有通过验证的用户才能访问后端服务。 (见上面的示例代码)
自定义日志过滤器 (LogFilterFactory) 记录请求信息,例如请求URI、请求头、请求体等,方便排查问题。 (见上面的示例代码)

希望这些示例能够帮助大家更好地理解和使用Spring Cloud Gateway的自定义过滤器!

好了,今天就到这里,咱们下次再见!👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注