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工作原理:
CacheRequestBody提取请求体。- 将其转换为指定的
bodyClass(如上例中定义的java.lang.String)。 - 然后,它将转换后的对象放入
ServerWebExchange.getAttributes()的属性中,键名为ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR。
注意
此过滤器仅适用于 HTTP(包括 HTTPS)请求。
补充教学 —— 为什么要缓存请求体?
在 Spring WebFlux(响应式编程)中,请求体是一个数据流(Flux/Mono)。流是一次性的,就像水流过管子一样,流过去就没了。
- 问题场景:假设你有一个过滤器需要打印请求日志(包含请求体内容),然后请求继续转发给微服务。
- 如果过滤器读取了流来打印日志,流就“干涸”了。
- 当请求到达微服务时,微服务去读请求体,发现里面是空的,导致报错。
- 解决方案:使用
CacheRequestBody。- 它把流读出来,存到一个变量(缓存)里。
- 然后它会“重造”一个新的流传给下游。
- 这样,过滤器可以读缓存,下游微服务可以读重造的流,互不干扰。