Gateway 过滤器深入
概述
Spring Cloud Gateway 的过滤器分为 GatewayFilter(路由级)和 GlobalFilter(全局级)。过滤器链在 FilteringWebHandler 中按顺序执行,是网关实现横切关注点的核心机制。
过滤器体系
GatewayFilter (路由级)
├── 内置工厂: AddRequestHeader, StripPrefix, RequestRateLimiter...
├── 自定义: 实现 GatewayFilter 接口
└── 组合: 多个 GatewayFilter 链
GlobalFilter (全局级)
├── 内置: NettyRoutingFilter, ForwardRoutingFilter...
└── 自定义: 实现 GlobalFilter + Ordered一、GlobalFilter 全局过滤器
1.1 鉴权过滤器
java
@Component
@Order(-100) // 高优先级,前置执行
public class AuthGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 白名单放行
if (path.startsWith("/auth/") || path.startsWith("/public/")) {
return chain.filter(exchange);
}
// 检查 Token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange, "Missing or invalid token");
}
// 验证 JWT
try {
Jwt jwt = jwtDecoder.decode(token.substring(7));
// 将用户信息注入 Header(透传给下游服务)
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", jwt.getSubject())
.header("X-User-Name", jwt.getClaimAsString("name"))
.header("X-User-Role", jwt.getClaimAsString("role"))
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
} catch (JwtException e) {
return unauthorized(exchange, "Token expired or invalid");
}
}
private Mono<Void> unauthorized(ServerWebExchange exchange, String msg) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse()
.writeWith(Mono.just(exchange.getResponse()
.bufferFactory().wrap(("{\"error\":\"" + msg + "\"}").getBytes())));
}
}1.2 限流过滤器
java
@Component
@Order(-50)
public class RateLimitGlobalFilter implements GlobalFilter {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String KEY_PREFIX = "gateway:rate:";
private static final int MAX_REQUESTS = 100;
private static final int WINDOW_SECONDS = 1;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String ip = exchange.getRequest().getRemoteAddress() != null
? exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
: "unknown";
String key = KEY_PREFIX + ip;
return Mono.fromRunnable(() -> {
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) {
redisTemplate.expire(key, WINDOW_SECONDS, TimeUnit.SECONDS);
}
exchange.getAttributes().put("request_count", count);
}).then(chain.filter(exchange));
}
}1.3 日志过滤器(全链路 TraceId)
java
@Component
@Order(Ordered.LOWEST_PRECEDENCE) // 低优先级,后置执行
public class LoggingGlobalFilter implements GlobalFilter {
private static final Logger log = LoggerFactory.getLogger("GATEWAY_LOG");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 生成或透传 TraceId
String traceId = exchange.getRequest().getHeaders()
.getFirst("X-Trace-Id");
if (traceId == null || traceId.isEmpty()) {
traceId = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
}
// 注入 TraceId 到请求头
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-Trace-Id", traceId)
.build();
// 注入 MDC(用于日志打印)
MDC.put("traceId", traceId);
long start = System.currentTimeMillis();
return chain.filter(exchange.mutate().request(request).build())
.doFinally(signalType -> {
long duration = System.currentTimeMillis() - start;
log.info("[{}] {} {} -> {} ({}ms)",
traceId,
request.getMethod(),
request.getURI().getPath(),
exchange.getResponse().getStatusCode(),
duration);
MDC.remove("traceId");
});
}
}1.4 响应封装过滤器
java
@Component
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class ResponseWrapperGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 只包装 JSON 响应
if (!isJsonResponse(exchange)) {
return chain.filter(exchange);
}
ServerHttpResponse originalResponse = exchange.getResponse();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
// 包装原始响应为统一格式
String originalBody = decodeBody(dataBuffers);
String wrappedBody = "{\"code\":200,\"data\":" + originalBody + "}";
return originalResponse.bufferFactory()
.wrap(wrappedBody.getBytes(StandardCharsets.UTF_8));
}));
}
return super.writeWith(body);
}
};
return chain.filter(exchange.mutate().response(decoratedResponse).build());
}
}二、自定义过滤器工厂
2.1 基本结构
java
@Component
public class CheckHeaderGatewayFilterFactory
extends AbstractGatewayFilterFactory<CheckHeaderGatewayFilterFactory.Config> {
public CheckHeaderGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String headerValue = exchange.getRequest()
.getHeaders().getFirst(config.getHeaderName());
if (headerValue == null || !headerValue.matches(config.getRegex())) {
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
};
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("headerName", "regex");
}
@Data
public static class Config {
private String headerName;
private String regex;
}
}2.2 使用
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- CheckHeader=X-Source,order-service|product-service
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20三、内置过滤器详解
3.1 RequestRateLimiter 限流
yaml
spring:
cloud:
gateway:
routes:
- id: rate-limited-route
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100 # 每秒令牌数
redis-rate-limiter.burstCapacity: 200 # 突发令牌数
redis-rate-limiter.requestedTokens: 1 # 每次请求消耗令牌数
key-resolver: "#{@userKeyResolver}" # 限流 Key 解析器java
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
String userId = exchange.getRequest().getHeaders()
.getFirst("X-User-Id");
return Mono.just(userId != null ? userId : "anonymous");
};
}3.2 CircuitBreaker 熔断
yaml
spring:
cloud:
gateway:
routes:
- id: circuit-breaker-route
uri: lb://unstable-service
predicates:
- Path=/api/unstable/**
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallbackjava
@RestController
public class FallbackController {
@PostMapping("/fallback")
public Mono<Map<String, Object>> fallback(ServerWebExchange exchange) {
Throwable exception = exchange.getAttribute(
CircuitBreakerExecutionException.class.getName());
return Mono.just(Map.of(
"code", 503,
"message", "Service temporarily unavailable",
"detail", exception != null ? exception.getMessage() : "unknown"
));
}
}3.3 Retry 重试
yaml
spring:
cloud:
gateway:
routes:
- id: retry-route
uri: lb://retry-service
predicates:
- Path=/api/retry/**
filters:
- name: Retry
args:
retries: 3 # 重试次数
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE,GATEWAY_TIMEOUT
methods: GET # 仅对 GET 重试(幂等安全)
backoff:
firstBackoff: 100ms # 首次延迟
maxBackoff: 1000ms # 最大延迟
factor: 2 # 指数退避因子
basedOnPreviousValue: false3.4 请求/响应修改
yaml
spring:
cloud:
gateway:
routes:
- id: modify-route
uri: lb://target-service
predicates:
- Path=/api/**
filters:
# 请求头
- AddRequestHeader=X-Gateway-Source, api-gateway
- RemoveRequestHeader=X-Internal-Token
# 请求参数
- AddRequestParameter=trace, true
# 路径
- StripPrefix=1 # 去除第一级路径
- PrefixPath=/v2 # 添加前缀
# 响应
- AddResponseHeader=X-Gateway-Version, 1.0
- RemoveResponseHeader=X-Powered-By
- SetResponseHeader=X-Frame-Options, DENY
# 状态码
- SetStatus=BAD_GATEWAY四、实战:通用过滤器链
4.1 过滤器链顺序
Order Filter 职责
─────────────────────────────────────────────────
-200 AuthGlobalFilter JWT 鉴权 + 用户信息注入
-150 RateLimitGlobalFilter 限流(IP + 用户双重维度)
-100 CheckHeader Filter 请求头校验
-50 CircuitBreaker Filter 熔断降级
0 Retry Filter 重试
50 LoggingGlobalFilter 全链路 TraceId + 耗时日志
100 ResponseWrapper Filter 统一响应格式
200 NettyRoutingFilter 转发到下游服务(内置)4.2 配置整合
java
@Configuration
public class GatewayFilterChainConfig {
@Bean
@Order(-200)
public GlobalFilter authFilter() {
return (exchange, chain) -> { /* 鉴权 */ };
}
@Bean
@Order(-150)
public GlobalFilter rateLimitFilter() {
return (exchange, chain) -> { /* 限流 */ };
}
@Bean
@Order(50)
public GlobalFilter loggingFilter() {
return (exchange, chain) -> { /* 日志 */ };
}
}五、总结
| 知识点 | 说明 |
|---|---|
GlobalFilter | 全局过滤器,自动应用到所有路由 |
GatewayFilterFactory | 路由级过滤器工厂,支持参数配置 |
@Order | 控制过滤器执行顺序 |
| RequestRateLimiter | 基于 Redis 令牌桶的限流 |
| CircuitBreaker | 熔断降级,支持 fallback |
| Retry | 带指数退避的重试机制 |
| TraceId | 全链路追踪 ID 透传 |
| 响应封装 | 统一 JSON 响应格式 |
参考链接: