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) | 配置文件或代码 |
| 常见用途 | 认证、安全、全局日志、跨域 | 路径重写、服务特定的头修改、流量控制 |
| 灵活性 | 低(全局生效) | 高(可针对不同路由定制) |

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

相关推荐
九皇叔叔32 分钟前
Java循环结构全解析:从基础用法到性能优化
java·开发语言·性能优化
流星52112240 分钟前
GC 如何判断对象该回收?从可达性分析到回收时机的关键逻辑
java·jvm·笔记·学习·算法
csdn_aspnet40 分钟前
Java 圆台体积和表面积计算程序(Program for Volume and Surface area of Frustum of Cone)
java
杯莫停丶1 小时前
设计模式之:外观模式
java·设计模式·外观模式
乐之者v1 小时前
Mac常用软件
java·1024程序员节
TDengine (老段)1 小时前
TDengine 数据函数 ROUND 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·1024程序员节
TDengine (老段)1 小时前
TDengine 数学函数 RAND 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
從南走到北1 小时前
JAVA无人自助共享系统台球室源码自助开台约球交友系统源码小程序
java·微信·微信小程序·小程序·1024程序员节
JH30731 小时前
jvm,tomcat,spring的bean容器,三者的关系
jvm·spring·tomcat
野犬寒鸦1 小时前
从零起步学习MySQL || 第十章:深入了解B+树及B+树的性能优势(结合底层数据结构与数据库设计深度解析)
java·数据库·后端·mysql·1024程序员节