Gateway-过滤器

1.定义

网关过滤器是一种在执行路由转发前后,用于拦截和修改传入的 HTTP 请求或返回的 HTTP 响应的组件。可以把它想象成一个 AOP(面向切面编程)的概念,在请求的生命周期中的特定点插入自定义逻辑。

2.功能

  • 身份认证与安全: 验证请求的 Token(如 JWT),拒绝非法请求。
  • 监控与指标收集: 记录请求的响应时间、状态码,用于性能监控(如集成 Prometheus)。
  • 动态路由: 根据请求内容(如 Header、路径)将请求路由到不同的服务实例。
  • 负载均衡: 在可用服务实例之间分配流量。
  • 请求限流与熔断: 限制单位时间内的请求数量,或在后端服务不可用时提供降级响应。
  • 请求/响应转换: 修改请求头、请求体,或者修改响应头、响应体。
  • 日志记录: 记录详细的访问日志和审计信息。

3. 类型

在 Spring Cloud Gateway 中,过滤器主要分为两种:

a) 全局过滤器 (Global Filters)
  • 作用范围 : 应用于所有进入网关的路由,无需配置,自动生效。
  • 用途: 实现全局性的功能,如全局认证、全局日志、全局跨域配置等。
  • 实现方式 : 实现 GlobalFilter 接口,并声明为 @Component 或通过配置类添加。
b)实现:RtGlobalFilter

连包带类创建filter.RtGlobalFilter,实现GlobalFilter接口,这里以计算响应时间为例编码。

编写完计算响应耗时逻辑后,通过Component注解,将全局过滤器交给Spring容器管理

然后开启任意一个order微服务和Gateway微服务

浏览器访问http://localhost/api/order/readDb

然后可以看到,在控制台中已经成功计算了该请求-响应的耗时,19ms。

c) 网关过滤器 (Gateway Filters)
  • 作用范围 : 需要通过配置应用于特定路由 。通常在路由配置中通过 filters 字段声明。
  • 用途: 实现针对某个或某组路由的特定功能,如为某个服务添加请求头、重写路径等。
d) 实现:路径重写过滤器

我们首先注释ordercontroller的接口路径

启动所有微服务

启动完毕后,浏览器访问localhost/api/order/readDB

可以看到返回了404,因为api/order接口被注释掉了

接下来,我们就使用路径重写过滤器来解决这个问题

  • RewritePath=/api/order/(?<segment>.*),/${segment}:

它匹配任何以 /api/order/ 开头的路径

将 /api/order/ 之后的所有内容捕获到一个名为 segment 的分组中

(?<segment>.*) 是正则表达式的命名捕获组,用于匹配任意字符

例如:

捕获前 ------> 捕获后

/api/order/readDb → /readDb

/api/order/123/details → /123/details

/api/order/search?status=pending → /search?status=pending

然后,我们再来测试一下,看看是否可以成功访问

可以看到访问成功了,这就是路径重写过滤器的强大,它使得客户端请求的路径与网关对外暴露的路径可以不同,网关在转发前会将其"重写"为后端服务能够识别的正确路径。它还避免将内部微服务的复杂结构暴露给外部客户端,增强安全性。外部客户端无法看到内部完整接口,隐藏了内部核心接口。它也使得开发者在开发接口的时候,不用写多个重复的RequestMapping("/**/*"),而是将它们捕获到分组中,便于开发。

此外, 过滤器还提供了添加响应头响应参数等功能,下面我们来简单试试

这次我们来以writeDb测试,浏览器访问后,按F12,查看writeDb请求标头,我们可以看到响应标头携带了我们刚才在配置文件中添加的参数,X-Response-Default-Foo, Default-Bar

e) 自定义过滤器 (Custom Filters)

● 作用范围: 由开发者精确定义,可应用于单个路由、一组路由或全局。其作用域通过配置或注解灵活控制。

● 用途: 实现特定的业务逻辑,如接口权限校验、请求参数加解密、流量染色、特定API的限流等。

● 实现方式: 通常通过实现 GatewayFilter 接口或继承 AbstractGatewayFilterFactory 类来创建,并通过配置文件的 filters 项或代码方式绑定到指定路由。

f)实现:OnceTokenGatewayFilterFactory过滤器工厂

我们首先来看一下Spring Cloud Gateway 内置的过滤器工厂AddResponseHeaderGatewayFilterFactory,看看我们自定义一个过滤器工厂需要哪些操作

通过源码我们可以知道,看看我们自定义一个过滤器工厂需要继承抽象类AbstractNameValueGatewayFilterFactory,定义配置类,提供构造函数,实现apply()方法等

首先,需要在配置文件中添加一个自定义过滤器,这里以JWT令牌为例

引入JWT依赖

创建工具类,JWTutils

复制代码
package com.atguigu.gateway.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JWTutils {
    
    private static final Key SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    private static final long EXPIRATION_TIME = 86400000; // 24小时

    /**
     * 生成 JWT
     * @param claims 自定义声明
     * @return JWT 字符串
     */
    public static String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SECRET_KEY)
                .compact();
    }

    /**
     * 验证 JWT 并返回 Claims
     * @param token JWT 字符串
     * @return Claims 对象
     */
    public static Claims validateToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(SECRET_KEY)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 检查 JWT 是否过期
     * @param claims Claims 对象
     * @return 是否过期
     */
    public static boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }

    /**
     * 生成默认的 Claims(包含用户名和角色)
     * @param username 用户名
     * @param role 角色
     * @return Claims Map
     */
    public static Map<String, Object> generateClaims(String username, String role) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username);
        claims.put("role", role);
        return claims;
    }
}

创建 OnceTokenGatewayFilterFactory继承AbstractNameValueGatewayFilterFactory,并实现apply方法,编写相关逻辑

启动订单微服务和网关微服务

浏览器访问,同时F12打开开发者工具查看,readDb请求--响应

可以看到请求头中已经携带了Token,通过控制台中我们也可以看到响应头和token。

4.总结

|----------|-----------------------|------------------------|
| 特性 | 全局过滤器 (Global Filter) | 网关过滤器 (Gateway Filter) |
| 作用范围 | 所有路由 | 特定配置的路由 |
| 配置方式 | 代码声明(@Component) | 配置文件或代码 |
| 常见用途 | 认证、安全、全局日志、跨域 | 路径重写、服务特定的头修改、流量控制 |
| 灵活性 | 低(全局生效) | 高(可针对不同路由定制) |

过滤器是网关的"肌肉"和"大脑",它将网关从一个简单的路由器转变为一个强大的策略执行点,是构建现代化、可观测、安全的微服务系统的基石。

相关推荐
hssfscv3 小时前
JAVA学习笔记——9道综合练习习题+二维数组
java·笔记·学习
初听于你5 小时前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
小蒜学长6 小时前
springboot多功能智能手机阅读APP设计与实现(代码+数据库+LW)
java·spring boot·后端·智能手机
zizisuo8 小时前
解决在使用Lombok时maven install 找不到符号的问题
java·数据库·maven
笨蛋少年派9 小时前
JAVA基础语法
java·开发语言
渡我白衣9 小时前
深入剖析:boost::intrusive_ptr 与 std::shared_ptr 的性能边界和实现哲学
开发语言·c++·spring
Haooog9 小时前
654.最大二叉树(二叉树算法)
java·数据结构·算法·leetcode·二叉树
我真的是大笨蛋9 小时前
依赖倒置原则(DIP)
java·设计模式·性能优化·依赖倒置原则·设计规范
邂逅星河浪漫9 小时前
【RabbitMQ】docker-compose编排部署RabbitMQ容器——CentOS
分布式·docker·centos·rabbitmq·docker-compose