解决多次读取request输入流 : getInputStream/getReader() has already been called for this request

需求

实际开发中可能需要多次读取request中的输入流进行参数校验和修改,但HttpServletRequest是只能被读取一次

问题

public java.io.BufferedReader getReader()
    Throws:
    java.lang.IllegalStateException - if getInputStream() method has been called on this request

 public ServletInputStream getInputStream()
    Throws:
    java.lang.IllegalStateException - if the getReader() method has already been called for this request

解决方法

总体是克隆请求并通过filter再继续传递下去

step 1:

添加RepeatedlyReadRequestWrapper 类并继承 HttpServletRequestWrapper 包装类

public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {

    private final String body;

    /**
     *
     * @param request
     */
    public RepeatedlyReadRequestWrapper(HttpServletRequest request) throws IOException{
        super(request);
        StringBuilder sb = new StringBuilder();
        InputStream ins = request.getInputStream();
        BufferedReader isr = null;
        try{
            if(ins != null){
                isr = new BufferedReader(new InputStreamReader(ins));
                char[] charBuffer = new char[128];
                int readCount;
                while((readCount = isr.read(charBuffer)) != -1){
                    sb.append(charBuffer,0,readCount);
                }
            }
        }catch (IOException e){
            throw e;
        }finally {
            if(isr != null) {
                isr.close();
            }
        }

        sb.toString();
        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 false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() {
                return byteArrayIns.read();
            }
        };
        return  servletIns;
    }
}

step 2:

实现Filter传递请求

@WebFilter("/*")
public class ReadBodyHttpServletFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        RepeatedlyReadRequestWrapper requestWrapper = new RepeatedlyReadRequestWrapper(httpServletRequest);
        filterChain.doFilter(requestWrapper, httpServletResponse);
    }

    @Override
    public void destroy() {
    }
}

这里采用了通过继承OncePerRequestFilter方式来实现Filter,另外,直接实现Filter。

Reference

https://blog.csdn.net/liangxw1/article/details/51095484

https://blog.csdn.net/beflyabot/article/details/78053130

https://blog.csdn.net/qq_18495465/article/details/78470939

你可能感兴趣的:(解决多次读取request输入流 : getInputStream/getReader() has already been called for this request)