Http Servlet request lose params from POST body after read it once

前端 未结 13 2219
一个人的身影
一个人的身影 2020-11-22 14:56

I\'m trying to accessing two http request parameters in a Java Servlet filter, nothing new here, but was surprised to find that the parameters have already been consumed! Be

13条回答
  •  臣服心动
    2020-11-22 15:50

    The method getContentAsByteArray() of the Spring class ContentCachingRequestWrapper reads the body multiple times, but the methods getInputStream() and getReader() of the same class do not read the body multiple times:

    "This class caches the request body by consuming the InputStream. If we read the InputStream in one of the filters, then other subsequent filters in the filter chain can't read it anymore. Because of this limitation, this class is not suitable in all situations."

    In my case more general solution that solved this problem was to add following three classes to my Spring boot project (and the required dependencies to the pom file):

    CachedBodyHttpServletRequest.java:

    public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
    
        private byte[] cachedBody;
    
        public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
            super(request);
            InputStream requestInputStream = request.getInputStream();
            this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return new CachedBodyServletInputStream(this.cachedBody);
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            // Create a reader from cachedContent
            // and return it
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody);
            return new BufferedReader(new InputStreamReader(byteArrayInputStream));
        }
    }
    

    CachedBodyServletInputStream.java:

    public class CachedBodyServletInputStream extends ServletInputStream {
    
        private InputStream cachedBodyInputStream;
    
        public CachedBodyServletInputStream(byte[] cachedBody) {
            this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody);
        }
    
        @Override
        public boolean isFinished() {
            try {
                return cachedBodyInputStream.available() == 0;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return false;
        }
    
        @Override
        public boolean isReady() {
            return true;
        }
    
        @Override
        public void setReadListener(ReadListener readListener) {
            throw new UnsupportedOperationException();
        }
    
        @Override
        public int read() throws IOException {
            return cachedBodyInputStream.read();
        }
    }
    

    ContentCachingFilter.java:

    @Order(value = Ordered.HIGHEST_PRECEDENCE)
    @Component
    @WebFilter(filterName = "ContentCachingFilter", urlPatterns = "/*")
    public class ContentCachingFilter extends OncePerRequestFilter {
    
        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
            System.out.println("IN  ContentCachingFilter ");
            CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(httpServletRequest);
            filterChain.doFilter(cachedBodyHttpServletRequest, httpServletResponse);
        }
    }
    

    I also added the following dependencies to pom:

    
        org.springframework
        spring-webmvc
        5.2.0.RELEASE
    
    
        javax.servlet
        javax.servlet-api
        4.0.1
    
    
        com.fasterxml.jackson.core
        jackson-databind
        2.10.0
    
    

    A tuturial and full source code is located here: https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times

提交回复
热议问题