Get HttpServletRequest Body Multiple Times

Recently I came across a requirement in which I have to read HttpServletRequest body twice and then pass the request again to the filter chain for the normal application flow. Then I created the below given Java class which can be used inside a servlet filter to intercept the request, read request body content and then pass the request again to the servlet filter chain for further processing.

We must be aware, by default, the HTTP request body can be read only once. If we read the body in a filter, the target servlet will not be able to re-read it and this will also cause IllegalStateException.

1. Custom HttpServletRequestWrapper

This is the source code of the custom implementation of HttpServletRequestWrapper class. Please note that I am using Servlets 2.5 specification here because I had to work on some legacy applications. Feel free to change the implementation as per the latest servlet specification.

Overall, the wrapper class retrieves the request body and stores in the instance variable body. We can read the body attribute as many times, as we want without getting any errors.

This class can be seen as an example of reading InputStream twice, but it is not.

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class RequestWrapper extends HttpServletRequestWrapper {
	private final String body;

	public RequestWrapper(HttpServletRequest request) throws IOException
	{
		//So that other request method behave just like before
		super(request);

		StringBuilder stringBuilder = new StringBuilder();
		BufferedReader bufferedReader = null;
		try {
			InputStream inputStream = request.getInputStream();
			if (inputStream != null) {
				bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
				char[] charBuffer = new char[128];
				int bytesRead = -1;
				while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
					stringBuilder.append(charBuffer, 0, bytesRead);
				}
			} else {
				stringBuilder.append("");
			}
		} catch (IOException ex) {
			throw ex;
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException ex) {
					throw ex;
				}
			}
		}
		//Store request pody content in 'body' variable
		body = stringBuilder.toString();
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
		ServletInputStream servletInputStream = new ServletInputStream() {
			public int read() throws IOException {
				return byteArrayInputStream.read();
			}
		};
		return servletInputStream;
	}

	@Override
	public BufferedReader getReader() throws IOException {
		return new BufferedReader(new InputStreamReader(this.getInputStream()));
	}

	//Use this method to read the request body N times
	public String getBody() {
		return this.body;
	}
}

2. HttpServletRequestWrapper Usage

Use the wrapper class to modify request parameters in the servlet filter. It will help to servlet read the request body twice.

To use this class, we must first add a servlet filter filter mapping in web.xml. We will use the wrapper class inside this filter.

<filter>
	<filter-name>cacheFilter</filter-name>
	<filter-class>com.howtodoinjava.filter.RESTCacheFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>cacheFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

Above filter mapping will invoke the filter at all requests because we mapped it to wildcard /*.

3. Reading Request body Multiple Times

In the servlet filter, we can read the HTTP request body N number of times and then pass it to the filter chain and it will work just fine.

It’s a small utility class and may not be needed in most cases. But when it’s needed – you will know it.

public class CacheFilter implements Filter {

	private static final Logger LOGGER = LoggerFactory.getLogger(CacheFilter.class);
	private static final String INDEX_DIR = "c:/temp/cache";

	private FilterConfig filterConfig = null;

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		request = new RequestWrapper((HttpServletRequest) request);

		//Read request.getBody() as many time you need

		chain.doFilter(request, response);
	}

	public void init(FilterConfig filterConfiguration) throws ServletException {
		this.filterConfig = filterConfiguration;
	}

	public void destroy() {
		this.filterConfig = null;
	}
}

4. Conclusion

Using above given HttpServletRequestWrapper, you can read the HTTP request body and then the servlet can still read it later. Essentially, request body content is cached inside the wrapper object so it can be N number of times in the complete request lifecycle.

Happy Learning !!

Leave a Comment

  1. Where does newly created BufferedReader in below method gets closed to have proper resource maintenance?

    @Override
    public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    Reply
  2. Hi,
    I used similar code for creating RequestWraper for our application to implement Req encryption on client side and decryption on server side. But i facing the issue when i upload an image or zip files they are getting corrupted.
    If i stop using RequestWrapper which is newly introduced, Upload and download files are working fine.
    I feel we need to do something here when request is “multipart”, Please help me what is the fix for this issue.
    Thanks in advance.

    Reply
  3. In my case, I’m working on legacy code and need to make a patch. The problem: an ancient application sends bad HTTP POST requests. I need to always read the http POST data and update it with the correct post and sent back to REST endpoint. If I read data once, then I am not able to read it again. Can you please guide me on this ?

    Reply
  4. I have an error in the request = new RequestWrapper (HttpServletRequest) request
    error is RequestWrapper (org.apache.http.HttpRequest) in RequestWrapper can not be applied to javax.servlet.http.HttpServletRequest
    knowing that for the RequestWrapper I used the following import: org.apache.http.impl.client.RequestWrapper

    Reply
  5. There’s quite a few drawbacks to this if used with Tomcat 8.
    Once you get the InputStream from the original request, then you can’t use getParameter(), unless you parse them on your own.
    If you first invoke getParameter to try and get them parsed, and then call getInputStream on the original request, you’ll get a stream that has already reached its end, and you can’t read it again.

    I was hoping to use this to re-read bodies and send them as attachments when my error filter catches something. It will take a lot more code to get it to parse the bodies for parameters.

    Reply
  6. Hi I trying same code on Web Sphere application server but it is not working. Once the request is read it when I chain the request values goes null there.

    Reply
  7. Let me know if we can use this modification:

    public RequestWrapper(HttpServletRequest request) throws IOException 
    	{
    		super(request);
    		try {
    			body = IOUtils.toString(request.getInputStream());
    		} catch (IOException ex) {
    			throw ex;
    		} 
    	}
    
    Reply
  8. I have 2 filters, and I used your code in one of them, eactly like you did in your example. The first time the filter is called, I read body without problem, but when call chain.doFilter the wrapper is called again, and this time (second time) the line “while …” throw an exception because the stream is closed. I have commented the line where bufferedreader is closed and everything works fine. So, I’d like to know why the wrapper was called twice? And how to close the bufferedreader without close inputstream who have been passed in constructor?

    Reply

Leave a Comment

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode