异常:getReader() has already been called for this request

本文介绍了一种解决框架或拦截器中出现的流数据重复读取异常的方法。通过自定义过滤器,将原始请求流读取并缓存到数组中,重写getInputStream()和getReader()方法,确保二次读取时数据仍然可用。
摘要由CSDN通过智能技术生成

一个流不能读两次异常,这种异常一般出现在框架或者拦截器中读取了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>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值