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 !!

Comments

Subscribe
Notify of
guest
11 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

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.