1. 概述

Spring Cloud Gateway 是微服务架构中常用的智能代理服务,它将所有请求汇聚到一个统一入口,再透明地路由到对应的后端服务。其核心能力之一就是 过滤器机制,即 WebFilterGatewayFilter

这些过滤器配合 路由断言(Predicate)工厂,构成了完整的请求路由与处理流程。✅ Spring Cloud Gateway 提供了大量内置的 WebFilter 工厂,允许我们在请求到达目标服务前修改请求,或在响应返回客户端前处理响应体与头部信息。当然,你也可以实现自定义过滤器来满足更复杂的业务需求。

本文将聚焦 Spring Cloud Gateway 内置的 WebFilter 工厂,结合高级使用场景,深入讲解它们的用法和踩坑点。


2. WebFilter 工厂简介

WebFilter(也称 GatewayFilter)工厂用于修改进入网关的 HTTP 请求和从后端服务返回的响应。它们在请求转发前后执行,为微服务提供诸如鉴权、限流、头信息处理等通用能力。

Spring Cloud Gateway WebFilter Factories Architecture

如上图所示,整个流程如下:

  1. Handler Mapping 接收客户端请求,判断是否匹配某个已配置的路由。
  2. 若匹配成功,则将请求交给 Web Handler 处理,并执行该路由对应的过滤器链。
  3. 虚线部分区分了 前置过滤器(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


原始标题:Spring Cloud Gateway WebFilter Factories | Baeldung