Spring Boot 3.4.2:ContentCachingRequestWrapper读取请求体后返回已耗尽InputStream而非新流的问题咨询
Spring Boot 3.4.2:ContentCachingRequestWrapper读取请求体后返回已耗尽InputStream而非新流的问题咨询
我正在开发一个基于Spring Boot 3.4.2的应用,使用ContentCachingRequestWrapper来支持多次读取请求体,但遇到了一个问题——请求体被读取一次后(比如通过过滤器或拦截器),后续所有读取操作都返回空流(read() == -1)。
问题场景细节
- 过滤器或拦截器将请求包装成
ContentCachingRequestWrapper - 早期的组件(在我的场景中是一个预处理处理器,负责解析请求类型)通过
request.getReader()读取了一次请求体,最终调用到一个自定义的CachedBodyServletRequest类(基于Spring多读取请求体的实现思路) - 后续在过滤器链中,Spring尝试执行
readWithMessageConverters时,会创建一个EmptyBodyCheckingHttpInputMessage,它会调用request.getBody,进而调用CachedBodyServletRequest对象的getInputStream()方法,此时返回-1,导致后续逻辑因请求体为null而失败,抛出HttpMessageNotReadable异常 - 调试发现
ContentCachingRequestWrapper#getInputStream()中有这样的条件判断:
public ServletInputStream getInputStream() throws IOException { if (this.inputStream == null) { this.inputStream = new ContentCachingInputStream(getRequest().getInputStream()); } return this.inputStream; }
由于预处理处理器首次读取后inputStream不为null,Spring返回的是同一个已耗尽的流,而非创建新流,但getContentAsByteArray()仍然包含完整的请求体。
我原本以为ContentCachingRequestWrapper缓存了请求体后,getInputStream()会返回一个可以多次读取的全新InputStream,就像getContentAsByteArray()那样。
观察到的行为
- 如果某个组件提前读取了请求体,后续调用
getInputStream()会返回空流(read() == -1) - 即使请求体已经被缓存,Spring也不会刷新InputStream
疑问
这是ContentCachingRequestWrapper的预期行为吗?
如果是,那么重置或刷新InputStream供后续读取的最佳方式是什么?
这是Spring的bug,还是我对请求体缓存和过滤器链的理解存在根本性错误?
备注:内容来源于stack exchange,提问作者Rmorrison96
相关产品推荐
相关产品推荐

