SpringBootv2.2以上重复读取RequestBody内容的解决⽅
⽬录
SpringBootv2.2以上重复读取RequestBody内容
⼀、需求
⼆、解决⽅案
三、遇到问题
四、问题排查
解决⽅案
SpringBoot读取Request参数的坑
后端拿参数相关
关于流
SpringBoot v2.2以上重复读取Request Body内容
⼀、需求
spring怎么读取jar文件
项⽬有两个场景会⽤到从Request的Body中读取内容。
打印请求⽇志
提供Api接⼝,在api⽅法执⾏前,从Request Body中读取参数进⾏验签,验签通过后在执⾏api⽅法
⼆、解决⽅案
2.1 ⾃定义RequestWrapper
public class MyRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = ad(request);
}
public String getBody() {
return body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new Bytes());
return new ServletInputStream() {
...略
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStream()));
}
}
RequestReadUtils(⽹上抄的)
private static final int BUFFER_SIZE = 1024 * 8;
public static String read(HttpServletRequest request) throws IOException {
BufferedReader bufferedReader = Reader();
for (Enumeration<String> iterator = HeaderNames(); iterator.hasMoreElements();) {
String type = Element();
System.out.println(type+" = "+Header(type));
}
System.out.println();
StringWriter writer = new StringWriter();
write(bufferedReader,writer);
Buffer().toString();
}
public static long write(Reader reader,Writer writer) throws IOException {
return write(reader, writer, BUFFER_SIZE);
public static long write(Reader reader, Writer writer, int bufferSize) throws IOException
{
int read;
long total = 0;
char[] buf = new char[bufferSize];
while( ( read = ad(buf) ) != -1 ) {
writer.write(buf, 0, read);
total += read;
}
return total;
}
2.2 定义Filter
@WebFilter
public class TestFilter implements Filter{
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain){
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
MyRequestWrapper wrapper = NativeRequest(request, MyRequestWrapper.class);
chain.doFilter(wrapper == null ? new MyRequestWrapper(request) :wrapper,servletRequest);
}
}
三、遇到问题
使⽤的SpringBoot v2.1.x版本
Form提交⽆问题
获取RequestBody⽆问题
使⽤SpringBoot v2.2.0以上版本(包括v2.3.x)
Form提交⽆法获取参数
获取RequestBody⽆问题
四、问题排查
经过排查,v2.2.x对⽐v2.1.x的不同在于⼀下代码差异:
BufferedReader bufferedReader = Reader();
-----------------
char[] buf = new char[bufferSize];
while( ( read = ad(buf) ) != -1 ) {
writer.write(buf, 0, read);
total += read;
}
当表单提交时
v2.1.x⽆法read到内容,读取结果为-1
v2.2.x、v2.3.x能够读取到内容
当表单提交时(x-www-form-urlencoded),inputStream读取⼀次后后续不会触发wrapper的getInputStream操作,所以Controller⽆法获取到参数。
解决⽅案
MyRequestWrapper改造
public class MyRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = getBodyString(request);
}
public String getBody() {
return body;
public String getBodyString(final HttpServletRequest request) throws IOException {
String contentType = ContentType();
String bodyString = "";
StringBuilder sb = new StringBuilder();
if (StringUtils.isNotBlank(contentType) && (ains("multipart/form-data") || ains("x-www-form-urlencoded"))) {        Map<String, String[]> parameterMap = ParameterMap();
for (Map.Entry<String, String[]> next : Set()) {
String[] values = Value();
String value = null;
if (values != null) {
if (values.length == 1) {
value = values[0];
} else {
value = String(values);
}
}
sb.Key()).append("=").append(value).append("&");
}
if (sb.length() > 0) {
bodyString = sb.toString().substring(0, sb.toString().length() - 1);
}
return bodyString;
} else {
InputStream());
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new Bytes());
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public int read() {
ad();
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStream()));
}
}
SpringBoot 读取Request参数的坑
后端拿参数相关
默认配置时,
getInputStream()和getReader()⼀起使⽤会报错
使⽤两遍getInputStream(),第⼆遍会为空
当存在@RequestBody等注解时,springMVC已读取过⼀遍流,默认单独使⽤getInputStream()或getRe
ader()都为空。解决:写filter继承HttpServletRequestWrapper,缓存InputStream,覆盖getInputStream()和getReader()⽅法,使⽤ByteArrayInputStream is = new Bytes());读取InputStream。
注意:springboot中,过滤器只需@Component即可⽣效,另外可在FilterRegistrationBean中配置路径和优先级。
对于,必须在InterceptorRegistry中调⽤addInterceptor⽅法。(路径可链式添加)
关于流
只能读⼀遍,类似管⼦。
只承担传输职责,⽽与处理和存储⽆关。
对于byte流⽽⾔,进⾏重复读取易于实现,但指针不重置,应是为了与InputStream接⼝定义保持⼀致。以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。