0%

GateWay过滤器

Spring Cloud Gateway 过滤器:请求处理的拦截与增强机制

Spring Cloud Gateway 的过滤器(Filter)用于在请求路由前后对请求 / 响应进行拦截、修改或增强,是实现权限校验、日志记录、限流熔断等功能的核心组件。过滤器分为内置过滤器(官方提供)和自定义过滤器(按需扩展),按作用范围又可分为全局过滤器(对所有路由生效)和路由过滤器(仅对指定路由生效)。

过滤器的核心作用

  • 请求预处理:路由前修改请求头、参数、路径(如添加认证信息、统一前缀);
  • 响应后处理:路由后修改响应头、状态码(如添加跟踪 ID、统一响应格式);
  • 业务管控:实现限流、熔断、日志记录、权限校验等(如拦截未登录请求);
  • 异常处理:捕获路由过程中的异常,返回友好提示。

内置过滤器详解

Gateway 内置了数十种过滤器,按功能可分为以下类别,覆盖大部分常见场景:

1. 请求头 / 响应头过滤器

用于修改请求头或响应头信息,常见过滤器包括:

过滤器名称 作用说明 配置示例
AddRequestHeader 为请求添加指定头信息。 - AddRequestHeader=X-Request-Source, gateway(添加X-Request-Source: gateway
AddResponseHeader 为响应添加指定头信息。 - AddResponseHeader=X-Response-Time, {now}(添加响应时间头)
RemoveRequestHeader 移除请求中的指定头信息(如敏感信息)。 - RemoveRequestHeader=Authorization(移除 Authorization 头)
RemoveResponseHeader 移除响应中的指定头信息。 - RemoveResponseHeader=X-Powered-By(移除服务器标识头)
DedupeResponseHeader 处理重复的响应头(如 CORS 跨域头),支持RETAIN_FIRST(保留第一个)、RETAIN_LAST(保留最后一个)、RETAIN_UNIQUE(去重)策略。 - DedupeResponseHeader=Access-Control-Allow-Credentials, RETAIN_LAST

2. 请求参数过滤器

用于修改请求参数:

过滤器名称 作用说明 配置示例
AddRequestParameter 为请求添加指定参数。 - AddRequestParameter=source, gateway(添加?source=gateway
RemoveRequestParameter 移除请求中的指定参数。 - RemoveRequestParameter=secret(移除 secret 参数)

3. 路径过滤器

用于修改请求路径(路由前重写路径):

过滤器名称 作用说明 配置示例
PrefixPath 为请求路径添加前缀。 - PrefixPath=/api(将/dept变为/api/dept
StripPrefix 从请求路径中剥离指定层数的前缀。 - StripPrefix=1(将/api/dept变为/dept
RewritePath 用正则表达式重写路径(格式:原始正则, 目标路径)。 - RewritePath=/api/(?<segment>.*), /$\{segment}(将/api/dept变为/dept
SetPath 直接设置路径(支持占位符)。 - SetPath=/{segment}(从参数或路径中提取segment作为新路径)

4. 状态与重定向过滤器

过滤器名称 作用说明 配置示例
SetStatus 设置响应状态码(支持数字或枚举,如401UNAUTHORIZED)。 - SetStatus=403(返回 403 Forbidden)
RedirectTo 重定向请求到指定 URL(格式:状态码, 目标URL)。 - RedirectTo=302, https://example.com(302 重定向到example.com

5. 重试与限流过滤器

过滤器名称 作用说明 配置示例
Retry 当请求失败时重试(支持配置重试次数、重试状态码、重试方法等)。 - name: Retry<br> args:<br> retries: 3<br> statuses: BAD_GATEWAY(对 502 错误重试 3 次)
RequestRateLimiter 基于令牌桶算法限流(需结合 Redis),控制请求频率。 - name: RequestRateLimiter<br> args:<br> redis-rate-limiter.replenishRate: 10<br> redis-rate-limiter.burstCapacity: 20(每秒生成 10 个令牌,桶容量 20)

6. 其他常用过滤器

过滤器名称 作用说明 配置示例
SaveSession 路由前强制保存 Spring Session(适用于需要会话同步的场景)。 - SaveSession
SecureHeaders 添加安全相关的响应头(如X-Content-Type-OptionsX-Frame-Options)。 - SecureHeaders(默认添加一组安全头)

自定义过滤器

内置过滤器无法满足需求时,可自定义过滤器。按作用范围分为全局过滤器路由过滤器

1. 自定义全局过滤器

全局过滤器对所有路由生效,需实现GlobalFilterOrdered接口,无需在配置文件中配置。

示例:Token 校验全局过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component  // 注册为Spring Bean,自动生效
public class TokenGlobalFilter implements GlobalFilter, Ordered {

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

// 2. 校验token,无token则返回401
if (StringUtils.isBlank(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 401未授权
return exchange.getResponse().setComplete(); // 结束响应
}

// 3. 校验通过,继续执行后续过滤器
return chain.filter(exchange);
}

// 过滤器执行顺序:数值越小,越先执行(-2147483648 ~ 2147483647)
@Override
public int getOrder() {
return -100; // 优先于大多数内置过滤器执行
}
}

特点

  • 无需配置,系统启动时自动加载,作用于所有路由;
  • 适合实现全局功能(如统一认证、日志记录)。

2. 自定义路由过滤器

路由过滤器仅对指定路由生效,有两种实现方式:

(1)实现GatewayFilter接口(硬编码配置)

需手动在路由中绑定过滤器,适合简单场景。

示例:自定义路由过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class LoggingRouteFilter implements GatewayFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(LoggingRouteFilter.class);

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 路由前记录请求信息
log.info("Request: {} {}", exchange.getRequest().getMethod(), exchange.getRequest().getPath());

// 路由后记录响应信息(通过then()回调)
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
log.info("Response: {}", exchange.getResponse().getStatusCode());
}));
}

@Override
public int getOrder() {
return 0;
}
}

配置路由时绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service-route", r -> r
.path("/user/**")
.filters(f -> f.filter(new LoggingRouteFilter())) // 绑定自定义过滤器
.uri("lb://user-service")
)
.build();
}
}
(2)继承AbstractGatewayFilterFactory(支持配置文件)

通过配置文件指定参数,更灵活,适合复杂场景。

步骤 1:定义配置类(存储过滤器参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory<LoggingGatewayFilterFactory.Config> {

// 配置参数类
public static class Config {
private boolean logRequest; // 是否记录请求
private boolean logResponse; // 是否记录响应

// getter和setter
}

// 构造方法:指定配置类
public LoggingGatewayFilterFactory() {
super(Config.class);
}

// 实现过滤逻辑
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 路由前:记录请求(根据配置)
if (config.isLogRequest()) {
log.info("Request: {} {}", exchange.getRequest().getMethod(), exchange.getRequest().getPath());
}

// 路由后:记录响应(根据配置)
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
if (config.isLogResponse()) {
log.info("Response: {}", exchange.getResponse().getStatusCode());
}
}));
};
}

// 指定配置参数的顺序(与配置文件中的参数顺序对应)
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("logRequest", "logResponse");
}
}

步骤 2:注册过滤器(添加@Component

1
2
@Component // 自动注册为Spring Bean,名称默认是类名去掉"GatewayFilterFactory"(即"Logging")
public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory<...> { ... }

步骤 3:配置文件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
cloud:
gateway:
routes:
- id: user-route
uri: lb://user-service
predicates:
- Path=/user/**
filters:
- name: Logging # 对应过滤器名称(LoggingGatewayFilterFactory → Logging)
args:
logRequest: true # 记录请求
logResponse: true # 记录响应

过滤器执行顺序

过滤器的执行顺序由Ordered接口的getOrder()方法决定:

  • 数值越小,优先级越高(全局过滤器和路由过滤器共用同一顺序体系);
  • 路由过滤器中,配置在前面的过滤器先执行(同getOrder()时);
  • 执行阶段:pre(路由前)→ 路由 → post(路由后),全局过滤器和路由过滤器按顺序混合执行。

总结

Gateway 过滤器是实现网关功能的核心,内置过滤器覆盖了大部分常见场景(如头信息修改、路径重写、限流重试),自定义过滤器可满足个性化需求(如业务认证、日志审计)。

  • 全局过滤器:适合实现全局管控(如统一认证),无需配置,自动作用于所有路由;
  • 路由过滤器:适合针对特定路由的增强(如局部限流),需在路由中显式配置

欢迎关注我的其它发布渠道