Skip to content

CacheRequestBody GatewayFilter 工厂

在某些情况下,必须读取请求体(Request Body)。由于请求体通常只能读取一次(流式读取),如果后续的过滤器或处理逻辑还需要使用它,我们就需要缓存请求体。

你可以使用 CacheRequestBody 过滤器在发送请求到下游之前缓存请求体,并在之后通过 exchange 属性获取缓存的内容。

以下代码演示了如何使用 CacheRequestBody GatewayFilter:

Java 配置示例

java
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("cache_request_body_route", r -> r.path("/downstream/**")
            .filters(f -> f.prefixPath("/httpbin")
                .cacheRequestBody(String.class)) // 缓存并转换为 String
            .uri(uri))
        .build();
}

application.yml 配置示例

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: cache_request_body_route
        uri: lb://downstream
        predicates:
        - Path=/downstream/**
        filters:
        - name: CacheRequestBody
          args:
            bodyClass: java.lang.String

工作原理:

  1. CacheRequestBody 提取请求体。
  2. 将其转换为指定的 bodyClass(如上例中定义的 java.lang.String)。
  3. 然后,它将转换后的对象放入 ServerWebExchange.getAttributes() 的属性中,键名为 ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR

注意

此过滤器仅适用于 HTTP(包括 HTTPS)请求。

补充教学 —— 为什么要缓存请求体?

在 Spring WebFlux(响应式编程)中,请求体是一个数据流(Flux/Mono)。流是一次性的,就像水流过管子一样,流过去就没了。

  • 问题场景:假设你有一个过滤器需要打印请求日志(包含请求体内容),然后请求继续转发给微服务。
    • 如果过滤器读取了流来打印日志,流就“干涸”了。
    • 当请求到达微服务时,微服务去读请求体,发现里面是空的,导致报错。
  • 解决方案:使用 CacheRequestBody
    • 它把流读出来,存到一个变量(缓存)里。
    • 然后它会“重造”一个新的流传给下游。
    • 这样,过滤器可以读缓存,下游微服务可以读重造的流,互不干扰。

Based on Spring Framework.