前言
SpringBoot项目在使用了拦截器(比如读取请求流进行解码)后你会发现你在controller中使用了@RequestBody注解获取参数报如下错误:
拦截器 I/O error while reading input message; nested exception is java.io.IOException: Stream closed
原因就是IO流关闭只能读取一次
解决办法
定义包装类,将IO流保存起来,并重写getInputStream()方法
@Slf4j
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] requestBody;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
try (ServletInputStream inputStream = request.getInputStream()) {
this.requestBody = ByteStreams.toByteArray(inputStream);
}
}
@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream stream = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return stream.read();
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
定义过滤器将Request对象转成包装对象
@Slf4j
@WebFilter(filterName = "bodyReaderFilter", urlPatterns = "/*")
@Component
public class BodyReaderFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (!(request instanceof HttpServletRequest)) {
chain.doFilter(request, response);
return;
}
BodyReaderHttpServletRequestWrapper bodyReaderHttpServletRequestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(bodyReaderHttpServletRequestWrapper, response);
}
}
多说一句
过滤器和拦截器的顺序关系
-
Filter Pre (过滤器) chain.doFilter(request, response) 前的逻辑
-
service (Servlet) spring mvc的doService()方法,也是servlet的service()方法
-
dispatcher (SpringMVC) 请求分发
-
preHandle (拦截器) 进入interceptor
-
controller (控制器) 处理业务需求
-
postHandle (拦截器) 在controller逻辑后return ModelAndView前调整ModelAndView的内容
-
afterCompletion (过滤器) 在filter返回前执行
-
Filter After (过滤器) 过滤器执行后