1. 概述
Spring Cloud Gateway 是微服务架构中常用的智能代理服务,它将所有请求汇聚到一个统一入口,再透明地路由到对应的后端服务。其核心能力之一就是 过滤器机制,即 WebFilter
或 GatewayFilter
。
这些过滤器配合 路由断言(Predicate)工厂,构成了完整的请求路由与处理流程。✅ Spring Cloud Gateway 提供了大量内置的 WebFilter 工厂,允许我们在请求到达目标服务前修改请求,或在响应返回客户端前处理响应体与头部信息。当然,你也可以实现自定义过滤器来满足更复杂的业务需求。
本文将聚焦 Spring Cloud Gateway 内置的 WebFilter 工厂,结合高级使用场景,深入讲解它们的用法和踩坑点。
2. WebFilter 工厂简介
WebFilter(也称 GatewayFilter)工厂用于修改进入网关的 HTTP 请求和从后端服务返回的响应。它们在请求转发前后执行,为微服务提供诸如鉴权、限流、头信息处理等通用能力。
如上图所示,整个流程如下:
- Handler Mapping 接收客户端请求,判断是否匹配某个已配置的路由。
- 若匹配成功,则将请求交给 Web Handler 处理,并执行该路由对应的过滤器链。
- 虚线部分区分了 前置过滤器(Pre-filter) 与 后置过滤器(Post-filter):
- 前置过滤器在请求转发给下游服务前执行。
- 后置过滤器在收到下游响应后、返回给客户端前执行。
通过这些过滤器,我们可以在不修改后端服务的前提下,灵活增强网关功能。
3. WebFilter 工厂的实现方式
Spring Cloud Gateway 支持两种方式配置过滤器:
- ✅ YAML 配置:适合静态、常规路由规则。
- ✅ Java DSL:适合动态、复杂逻辑,尤其是需要编程式处理的场景(如修改请求/响应体)。
下面我们通过具体示例逐一介绍常用工厂。
3.1 请求相关过滤器
内置的 WebFilter 工厂允许我们灵活操作 HTTP 请求头和参数,常见操作包括:
操作 | 工厂名称 | 说明 |
---|---|---|
添加请求头 | AddRequestHeader |
若头不存在则添加 |
条件添加头 | AddRequestHeadersIfNotPresent |
4.0+ 版本支持,避免重复添加 |
映射请求头 | MapRequestHeader |
将一个头的值复制到另一个头 |
设置/覆盖头 | SetRequestHeader |
强制设置头值 |
删除请求头 | RemoveRequestHeader |
移除指定头 |
添加请求参数 | AddRequestParameter |
添加查询参数 |
删除请求参数 | RemoveRequestParameter |
移除指定参数 |
示例配置如下:
- id: add_request_header_route
uri: https://httpbin.org
predicates:
- Path=/get/**
filters:
- AddRequestHeader=My-Header-Good,Good
- AddRequestHeader=My-Header-Remove,Remove
- AddRequestHeadersIfNotPresent=My-Header-Absent:Absent
- AddRequestParameter=var, good
- AddRequestParameter=var2, remove
- MapRequestHeader=My-Header-Good, My-Header-Bad
- MapRequestHeader=My-Header-Set, My-Header-Bad
- SetRequestHeader=My-Header-Set, Set
- RemoveRequestHeader=My-Header-Remove
- RemoveRequestParameter=var2
使用 curl
验证效果:
$ curl http://localhost:8080/get
{
"args": {
"var": "good"
},
"headers": {
"Host": "localhost",
"My-Header-Bad": "Good",
"My-Header-Good": "Good",
"My-Header-Set": "Set"
},
"url": "https://localhost:8080/get?var=good"
}
✅ 结果分析:
var2
参数被移除,var
参数保留。My-Header-Good
的值被映射到My-Header-Bad
。My-Header-Remove
被删除。My-Header-Set
被覆盖为Set
。
⚠️ 注意:MapRequestHeader
是复制值,不是移动。
修改请求体(modifyRequestBody)
某些场景下需要修改请求体内容(如解密、格式转换),此时必须使用 Java DSL,因为涉及反序列化与异步处理。
示例:将请求体内容转为大写:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("modify_request_body", r -> r.path("/post/**")
.filters(f -> f.modifyRequestBody(
String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> Mono.just(new Hello(s.toUpperCase()))
))
.uri("https://httpbin.org"))
.build();
}
测试:
$ curl -X POST "http://localhost:8080/post" -i -d "Content"
# 响应中 body 内容变为 "CONTENT"
✅ 踩坑提示:modifyRequestBody
只能用于 POST/PUT 等有请求体的接口,且类型转换需确保兼容。
3.2 响应相关过滤器
与请求类似,我们也可以对响应头和响应体进行处理。
响应头操作
操作 | 工厂 | 说明 |
---|---|---|
添加响应头 | AddResponseHeader |
添加头信息 |
设置响应头 | SetResponseHeader |
覆盖或设置头 |
删除响应头 | RemoveResponseHeader |
移除指定头 |
重写响应头 | RewriteResponseHeader |
使用正则替换头值 |
去重响应头 | DedupeResponseHeader |
避免重复头(如 CORS) |
重写 Location 头 | RewriteLocationResponseHeader |
修正跳转地址 |
移除 JSON 属性 | RemoveJsonAttributesResponseBody |
4.0+,移除响应体中的敏感字段 |
完整示例:
- id: response_header_route
uri: https://httpbin.org
predicates:
- Path=/header/post/**
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
- SetResponseHeader=My-Header-Set, Set
- RemoveResponseHeader=My-Header-Remove
- RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=***
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
- RemoveJsonAttributesResponseBody=form,Accept,true
- AddResponseHeader=My-Header-Good,Good
- AddResponseHeader=My-Header-Set,Good
- AddResponseHeader=My-Header-Remove,Remove
- AddResponseHeader=My-Header-Rewrite,password=12345678
- StripPrefix=1
验证响应头:
$ curl -X POST "http://localhost:8080/header/post" -s -o /dev/null -D -
HTTP/1.1 200 OK
My-Header-Good: Good
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
My-Header-Rewrite: password=***
My-Header-Set: Set
✅ RewriteResponseHeader
常用于脱敏,如将密码替换为 ***
。
修改响应体(modifyResponseBody)
同样需使用 Java DSL,适用于响应体转换、加密等场景。
示例:将 PUT 响应体替换为固定内容:
@Bean
public RouteLocator responseRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("modify_response_body", r -> r.path("/put/**")
.filters(f -> f.modifyResponseBody(
String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> Mono.just(new Hello("New Body"))
))
.uri("https://httpbin.org"))
.build();
}
测试:
$ curl -X PUT "http://localhost:8080/put" -i -d "CONTENT"
{"message":"New Body"}
⚠️ 注意:modifyResponseBody
会完全替换原始响应体,谨慎使用。
3.3 路径处理
路径类过滤器用于重写或调整请求路径,常用于前后端分离、API 版本管理等场景。
工厂 | 说明 |
---|---|
SetPath |
设置新路径 |
RewritePath |
使用正则重写路径 |
PrefixPath |
添加路径前缀 |
StripPrefix |
剥离前 N 级路径 |
示例:将 /new/post/**
映射到 /post
- id: path_route
uri: https://httpbin.org
predicates:
- Path=/new/post/**
filters:
- RewritePath=/new(?<segment>/?.*), $\{segment}
- SetPath=/post
测试:
$ curl -X POST "http://localhost:8080/new/post" -i
"url": "https://localhost:8080/post"
✅ 也可用 StripPrefix=1
实现类似效果,更简洁。
⚠️ 注意:YAML 中过滤器顺序即执行顺序,务必注意先后逻辑。
3.4 HTTP 状态控制
用于控制响应状态码或执行跳转。
工厂 | 说明 |
---|---|
RedirectTo |
30x 跳转,需指定状态码和目标 URL |
SetStatus |
设置响应状态码(如 401、403) |
示例:
- id: redirect_route
uri: https://httpbin.org
predicates:
- Path=/fake/post/**
filters:
- RedirectTo=302, https://httpbin.org
- id: status_route
uri: https://httpbin.org
predicates:
- Path=/delete/**
filters:
- SetStatus=401
验证跳转:
$ curl -X POST "http://localhost:8080/fake/post" -i
HTTP/1.1 302 Found
Location: https://httpbin.org
验证状态码:
$ curl -X DELETE "http://localhost:8080/delete" -i
HTTP/1.1 401 Unauthorized
3.5 请求大小限制
防止恶意大文件上传,保护后端服务。
- id: size_route
uri: https://httpbin.org
predicates:
- Path=/anything
filters:
- name: RequestSize
args:
maxSize: 5000000 # 5MB
✅ 若请求体超过限制,网关直接返回 413 Payload Too Large,不会转发到后端。
4. 高级使用场景
除了基础功能,Spring Cloud Gateway 还提供一系列高级 WebFilter 工厂,支撑微服务关键能力。
4.1 熔断器(Circuit Breaker)
集成 Resilience4J 实现服务熔断,避免雪崩。
- id: circuitbreaker_route
uri: https://httpbin.org
predicates:
- Path=/status/504
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/anything
- RewritePath=/status/504, /anything
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
✅ 当后端服务返回 504 时,自动降级到本地 /anything
接口。
4.2 重试机制(Retry)
网络抖动时自动重试,提升系统容错性。
- id: retry_test
uri: https://httpbin.org
predicates:
- Path=/status/502
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
✅ 支持按状态码、方法、异常类型重试,并可配置指数退避。
日志验证:
Handler is being applied: {uri=https://httpbin.org/status/502, method=GET} # 重试3次
4.3 会话与安全头
工厂 | 用途 |
---|---|
SaveSession |
在转发前持久化会话(配合 Spring Session/Security) |
SecureHeaders |
自动添加安全头(如 X-Frame-Options、X-Content-Type-Options) |
filters:
- SaveSession
✅ SaveSession
确保在调用下游服务前会话已保存,避免会话丢失。
4.4 请求限流(RequestRateLimiter)
基于 Redis 实现分布式限流,防止接口被刷。
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
Redis 配置:
spring:
redis:
host: localhost
port: 6379
限流配置(令牌桶算法):
- id: request_rate_limiter
uri: https://httpbin.org
predicates:
- Path=/redis/get/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒补充10个令牌
redis-rate-limiter.burstCapacity: 5 # 桶容量5
redis-rate-limiter.requestedTokens: 1 # 每次请求消耗1个
测试:
$ curl "http://localhost:8080/redis/get" -i
X-RateLimit-Remaining: 4
超过限制后返回 429 Too Many Requests
。
✅ 踩坑提示:确保 Redis 服务正常,否则限流失效。
4.5 缓存支持(4.0+)
从 4.0 版本开始,支持请求体和响应体缓存。
缓存请求体(CacheRequestBody)
- id: cache_request_body_route
uri: https://httpbin.org
predicates:
- Path=/cache/post/**
filters:
- StripPrefix=1
- name: CacheRequestBody
args:
bodyClass: java.lang.String
缓存后的请求体可通过 ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR
获取,供后续过滤器使用。
缓存响应体(LocalResponseCache)
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
全局配置:
spring:
cloud:
gateway:
filter:
local-response-cache:
enabled: true
timeToLive: 20m
size: 6MB
路由级覆盖:
- id: cache_response_body_route
uri: https://httpbin.org
predicates:
- Path=/cache/get/**
filters:
- StripPrefix=1
- LocalResponseCache=10s,20MB
✅ 访问后响应头会包含 Cache-Control: max-age=10
。
5. 总结
本文系统梳理了 Spring Cloud Gateway 内置的 WebFilter 工厂,涵盖请求/响应处理、路径重写、状态控制、熔断、重试、限流、缓存等核心功能。这些工厂极大提升了网关的灵活性与可扩展性。
✅ 关键点回顾:
- YAML 适合静态配置,Java DSL 适合复杂逻辑(如修改 body)。
- 过滤器顺序很重要,按 YAML 中声明顺序执行。
- 高级功能(如限流、熔断)需引入额外依赖。
- 4.0+ 版本增强了缓存与头处理能力。
所有示例代码已上传至 GitHub:
https://github.com/eugenp/tutorials/tree/master/spring-cloud-modules/spring-cloud-gateway