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

为什么ContentCachingRequestWrapper在Filter中输出为空但在Controller中正常

问题原因分析
  • ContentCachingRequestWrapper采用懒缓存机制:只有当请求输入流被主动读取时,才会将读取到的内容写入内部缓存字节数组,调用getContentAsByteArray()实际是读取这个内部缓存数组,不会主动拉取原始请求流的内容。
  • 你当前代码的执行顺序错误:在调用chain.doFilter()之前就尝试读取请求缓存,此时还没有任何组件读取过请求流,缓存数组未初始化,所以读到的是空字符串。
为什么Controller可以正常读取

chain.doFilter()会将包装后的请求传递到后续的Spring MVC处理链路,Spring MVC在解析@RequestBody参数时,会主动读取请求输入流,此时ContentCachingRequestWrapper会自动将读取到的内容写入内部缓存,所以到Controller执行时,缓存数组已经有值,读取自然正常。

同时你代码里的响应读取逻辑也存在同样的问题:在chain.doFilter()执行前响应还未被业务逻辑写入,读取ContentCachingResponseWrapper的缓存自然也是空值。

修复后的Filter代码
@Slf4j
@Component
public class ContentCachingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 先构造请求、响应包装类
        var wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
        var wrappedResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);

        try {
            // 优先执行后续链路,让请求被读取、响应被写入
            chain.doFilter(wrappedRequest, wrappedResponse);
        } finally {
            // 后续链路执行完成后再读取缓存内容
            var requestBody = new String(wrappedRequest.getContentAsByteArray(), StandardCharsets.UTF_8);
            log.debug("RequestBody: {}", requestBody);

            var responseBody = new String(wrappedResponse.getContentAsByteArray(), StandardCharsets.UTF_8);
            log.debug("ResponseBody: {}", responseBody);
            
            // 必须调用该方法将缓存的响应内容写回给客户端,否则客户端会收不到响应
            wrappedResponse.copyBodyToResponse();
        }
    }
}

注意:主动指定字符集可避免不同服务环境下的编码乱码问题。

内容的提问来源于stack exchange,提问作者Matthias Güntert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 09:27:03