为什么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
相关产品推荐
相关产品推荐

