HttpServletRequestWrapper example – read httpservletrequest twice

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

1. HttpServletRequestWrapper example

This is the sourcecode of 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 latest servlet specification.

This class cab be see as example to read 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 wrapper to modify request parameters in servlet filter. It will help to servlet read request body twice.

To use this class, you must first add a servlet filter mapping in web.xml.

<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. How to read request body twice in servlet filter

Now you can add a servlet filter java class in your code like this.

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;
	}
}

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

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

4. Summary

You must be aware, by deafult, the http request body can be read only once. If you read the body in a filter, the target servlet will not be able to re-read it and this will also cause IllegalStateException.

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

Drop me your questions in comments section.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

11 thoughts on “HttpServletRequestWrapper example – read httpservletrequest twice”

  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

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.