Spring-web 使用ContentCachingRequestWrapper包装HttpServletRequest,依旧出现HttpMessageNotReadableException: Required request body is missing的解决方案
这里先列出我的环境信息:
Group ID: org.springframework.boot Artifact ID: spring-boot Version: 3.5.0-SNAPSHOT
Group ID: org.springframework Artifact ID: spring-web Version: 6.2.7-SNAPSHOT
Group ID: org.springframework Artifact ID: spring-webmvc Version: 6.2.7-SNAPSHOT
我在过滤器Filter中使用ContentCachingRequestWrapper包装了HttpServletRequest类型的参数,
依旧不好用,还是会抛出 HttpMessageNotReadableException: Required request body is missing 错误。
原因在于我在过滤器中进行提前读取了请求体Body中的内容导致的。
因为你在过滤器提前消耗了请求流中的内容,在Controller层的控制器那里就获取不到流中的内容了。
我的控制器大概方法如下:
@PostMapping
void controller(@RequestBody String body)
反之,如果你不消耗流的话,ContentCachingRequestWrapper里的方法内容获取的都是空的。
如何提取消耗流的内容,让ContentCachingRequestWrapper实例有值呢?
答案就是wrappedRequest.getInputStream().readAllBytes();调用这个方法即可。
wrappedRequest是ContentCachingRequestWrapper的实例变量
也就是纵然是ContentCachingRequestWrapper对象,getInputStream方法也只能读取一次。
解决方法就是根据ContentCachingRequestWrapper实现,自己定义一个支持可重复读取流的方法。
这里直接给出Wrapper的示例,用法和ContentCachingRequestWrapper一样。
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.util.StreamUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.io.*;
/**
*
*/
public class JSONContentCachingRequestWrapper extends ContentCachingRequestWrapper {
public JSONContentCachingRequestWrapper(HttpServletRequest request) {
super(request);
}
public JSONContentCachingRequestWrapper(HttpServletRequest request, int contentCacheLimit) {
super(request, contentCacheLimit);
}
@Override
public BufferedReader getReader() throws IOException {
ServletInputStream inputStream = this.getInputStream();
if(inputStream.isFinished()){
byte[] contentAsByteArray = this.getContentAsByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(contentAsByteArray);
return new BufferedReader(new InputStreamReader(byteArrayInputStream, getCharacterEncoding()));
}
return super.getReader();
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream inputStream = super.getInputStream();
if(inputStream.isFinished()){
return new CachedBodyServletInputStream(super.getContentAsByteArray());
}
return inputStream;
}
public static class CachedBodyServletInputStream extends ServletInputStream {
private final ByteArrayInputStream cachedBodyInputStream;
public CachedBodyServletInputStream(byte[] cachedBody) {
this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody);
}
@Override
public boolean isFinished() {
return cachedBodyInputStream.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new UnsupportedOperationException();
}
@Override
public int read() throws IOException {
return cachedBodyInputStream.read();
}
}
}
参考资料:
https://stackoverflow.com/questions/63791808/required-request-body-is-missing-after-using-contentcachingrequestwrapper
https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times
出奇的,遇到这种问题的人不多哈。

浙公网安备 33010602011771号