You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux:大请求体场景下如何在WebFilter中获取请求体?

在WebFilter中正确获取大请求体的解决方案

嘿,我明白你现在遇到的问题了——直接用exchange.getRequest().getBody()拿到的请求体被截断了,这其实是Spring WebFlux的默认内存缓冲区限制在搞鬼,而且流式请求体只能被消费一次的特性也需要特别处理,下面给你一步步讲怎么解决:

1. 先调整请求体内存限制

Spring WebFlux默认限制了请求体的内存缓存大小(默认约256KB),如果你的请求体超过这个值,就会被截断。你需要在配置文件里增大这个限制:

在application.yml中配置:

spring:
  codec:
    max-in-memory-size: 10MB

或者在application.properties中:

spring.codec.max-in-memory-size=10MB

这个值可以根据你的实际请求体大小调整,比如设置成5MB、20MB都可以。

2. 正确读取并缓存请求体

因为WebFlux的请求体是Flux<DataBuffer>流式结构,一旦消费就无法再次读取,所以在WebFilter里读取请求体后,必须把它缓存起来,再包装成新的请求传递给后续的过滤器或处理器,避免后续流程拿不到请求体。

下面是完整的WebFilter示例代码:

import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component
public class FullRequestBodyFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest originalRequest = exchange.getRequest();

        // 合并所有DataBuffer成一个,完整读取请求体
        return DataBufferUtils.join(originalRequest.getBody())
                .flatMap(dataBuffer -> {
                    // 将DataBuffer转换成字节数组,方便后续使用
                    byte[] bodyBytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bodyBytes);
                    // 释放DataBuffer,避免内存泄漏
                    DataBufferUtils.release(dataBuffer);

                    // 创建缓存了请求体的包装请求
                    ServerHttpRequest cachedRequest = new CachedBodyServerHttpRequest(originalRequest, bodyBytes);

                    // 继续过滤器链,使用缓存后的请求
                    return chain.filter(exchange.mutate().request(cachedRequest).build())
                            // 异常时确保缓冲区被释放
                            .doOnError(error -> DataBufferUtils.release(dataBuffer));
                })
                // 处理请求体为空的情况,直接走原链
                .switchIfEmpty(chain.filter(exchange));
    }

    // 自定义请求包装类,用于缓存请求体
    private static class CachedBodyServerHttpRequest extends ServerHttpRequestDecorator {
        private final byte[] cachedBody;

        public CachedBodyServerHttpRequest(ServerHttpRequest delegate, byte[] cachedBody) {
            super(delegate);
            this.cachedBody = cachedBody;
        }

        @Override
        public Flux<DataBuffer> getBody() {
            return Flux.defer(() -> {
                // 将缓存的字节数组重新包装成DataBuffer
                DataBuffer buffer = DefaultDataBufferFactory.sharedInstance.wrap(cachedBody);
                // 确保缓冲区在被丢弃时释放
                return Flux.just(buffer).doOnDiscard(DataBuffer.class, DataBufferUtils::release);
            });
        }
    }
}

关键注意事项

  • 内存泄漏预防:一定要记得释放DataBuffer,WebFlux不会自动帮你释放,手动调用DataBufferUtils.release()或者通过doOnDiscard处理丢弃的情况,避免内存泄漏。
  • 超大请求体处理:如果你的请求体特别大(比如超过几十MB),不建议全部缓存到内存里,这时候可以考虑流式处理或者配置磁盘缓存,但这种场景比较少见,大部分业务场景调整内存限制+缓存就足够了。
  • 请求体重复读取:通过ServerHttpRequestDecorator包装请求后,后续的Controller或者其他过滤器都可以正常调用getRequest().getBody()获取请求体,不会因为被消费过而失效。

内容的提问来源于stack exchange,提问作者xiaoyu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:46:35