getInputStream/getReader() has already been called for this request
问题原因:HttpServletRequest是只能被读取一次,第二次读取就会报错。
实际开发中,需求场景:
1.代码在不同地方,需要多次读取request中的输入流进行参数校验和修改,第二次读取就会报错。
2.实际开发中,记录请求参数,把请求参数保存到日志中,利用spring aop,在切面内读取post请求参数。spring boot 在封装参数的时候已经读取一次,所以在切面内读取参数已经是第二次读取。
解决方法:
创建一个过滤器,创建一个spring包装过HttpServletRequest,在过滤中把请求参数复制到包装的request中,并通过filter把包装request再继续传递下去,
代码详细如下:
step 1:
创建包装的request, ReadHttpRequestWrapper 类并继承 HttpServletRequestWrapper 包装类
package com.one.order.filter;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class ReadHttpRequestWrapper extends HttpServletRequestWrapper {
private final String body;
/**
*
* @param request
*/
public ReadHttpRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder sb = new StringBuilder();
BufferedReader reader = request.getReader();
String readCount = "";
while((readCount = reader.readLine()) != null){
sb.append(readCount);
}
body = sb.toString();
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletIns = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(javax.servlet.ReadListener listener) {
}
@Override
public int read() {
return byteArrayIns.read();
}
};
return servletIns;
}
}
step 2:
创建Filter,往下传递请求;
这里采用了通过继承OncePerRequestFilter方式来实现Filter。
package com.one.order.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@WebFilter("/*")
public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ReadHttpRequestWrapper requestWrapper = new ReadHttpRequestWrapper(request);
filterChain.doFilter(requestWrapper, response);
}
}
step 3:
测试验证:
也可以在spring aop切面内或取请求参数,同样不报错。
/**
* 测试request.getReader
*/
@PostMapping("/list")
public void test(HttpServletRequest request) {
request.getReader(); // 不报错
return;
}