一个流不能读两次异常,这种异常一般出现在框架或者拦截器中读取了request中的流的数据,我们在业务代码中再次读取(如@requestBody),由于流中的数据已经没了,所以第二次读取的时候就会抛出异常。
解决方案:定义一个过滤器将流中的数据读取到一个数组中,并重写getInputStream()和getRead()方法,后续获取流中的数据的时候,直接去数组中读取,代码实现如下:
class DealStreamFilter extends AbstractWebFilter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
logger.info("进入DealStreamFilter。。。。。。");
ServletRequest requestWrapper = null;
if (servletRequest instanceof HttpServletRequest) {
requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) servletRequest);
}
if (null == requestWrapper) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
static class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = toByteArray(request.getInputStream());
}
private byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 4];
int n = 0;
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
};
}
}
}
将过滤器配置到配置文件:
<bean id="dealStreamFilter" class="com.pingan.apollo.filter.DealStreamFilter">
<property name="patterns" >
<list>
<value>/loan/device/report.do</value>
</list>
</property>
<property name="order" >
<value>-999999</value>
</property>
</bean>