How to retrieve raw post data from HttpServletRequest in java
The request body is available as byte stream by HttpServletRequest#getInputStream()
:
InputStream body = request.getInputStream();
// ...
Or as character stream by HttpServletRequest#getReader()
:
Reader body = request.getReader();
// ...
Note that you can read it only once. The client ain't going to resend the same request multiple times. Calling getParameter()
and so on will implicitly also read it. If you need to break down parameters later on, you've got to store the body somewhere and process yourself.
Http Servlet request lose params from POST body after read it once
As an aside, an alternative way to solve this problem is to not use the filter chain and instead build your own interceptor component, perhaps using aspects, which can operate on the parsed request body. It will also likely be more efficient as you are only converting the request InputStream
into your own model object once.
However, I still think it's reasonable to want to read the request body more than once particularly as the request moves through the filter chain. I would typically use filter chains for certain operations that I want to keep at the HTTP layer, decoupled from the service components.
As suggested by Will Hartung I achieved this by extending HttpServletRequestWrapper
, consuming the request InputStream
and essentially caching the bytes.
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedBytes;
public MultiReadHttpServletRequest(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (cachedBytes == null)
cacheInputStream();
return new CachedServletInputStream();
}
@Override
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
private void cacheInputStream() throws IOException {
/* Cache the inputstream in order to read it multiple times. For
* convenience, I use apache.commons IOUtils
*/
cachedBytes = new ByteArrayOutputStream();
IOUtils.copy(super.getInputStream(), cachedBytes);
}
/* An input stream which reads the cached request body */
private static class CachedServletInputStream extends ServletInputStream {
private final ByteArrayInputStream buffer;
public CachedServletInputStream(byte[] contents) {
this.buffer = new ByteArrayInputStream(contents);
}
@Override
public int read() {
return buffer.read();
}
@Override
public boolean isFinished() {
return buffer.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new RuntimeException("Not implemented");
}
}
}
Now the request body can be read more than once by wrapping the original request before passing it through the filter chain:
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
/* wrap the request in order to read the inputstream multiple times */
MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);
/* here I read the inputstream and do my thing with it; when I pass the
* wrapped request through the filter chain, the rest of the filters, and
* request handlers may read the cached inputstream
*/
doMyThing(multiReadRequest.getInputStream());
//OR
anotherUsage(multiReadRequest.getReader());
chain.doFilter(multiReadRequest, response);
}
}
This solution will also allow you to read the request body multiple times via the getParameterXXX
methods because the underlying call is getInputStream()
, which will of course read the cached request InputStream
.
Edit
For newer version of ServletInputStream
interface. You need to provide implementation of few more methods like isReady
, setReadListener
etc. Refer this question as provided in comment below.
How to modify HttpServletRequest body in java?
You can't change the request, but you could wrap it. See the following question for more details: Why do we wrap HttpServletRequest ? The api provides an HttpServletRequestWrapper but what do we gain from wrapping the request?
You will need to put a servlet filter in front of your servlet to make the wrapping work.
As for how to remove that part from the content, you could do it with plain old string manipulations from what the String
class offers, or with something like StringUtils, or you could parse the JSON with a library of your choice, remove that property, then write it back as a string.
How to detect if HttpServletRequest has body?
You can use getContentLength() or getContentLengthLong() and check if it is positive.
Related Topics
How to Make Program to Continue Running After Exception
How to Call a Function from Other Activity Android
How to Check Whether an Array Is Null/Empty
Error: Incompatible Types: Int[][] Cannot Be Converted to Int
Http 415 Unsupported Media Type Error With Json
How to Get the Autoincremented Id When I Insert a Record in a Table Via Jdbctemplate
Calling Method That Exists in Child Classes But Not in Parent Class
Open Pdf from Bytes Array in Angular 5
Ldap Query Get All Groups (Nested) of a Group
How to Handle Incorrect User Input into a Scanner
How to Check Type of Variable in Java
How to Check If an Int Is a Null
How to Click an Li Inside a Ul Using Selenium Webdriver
Wrong Answer in Task - Mistake in Algorithm
Reverse a String Without Affecting Special Characters
Creating a Composite Unique Constraints on Multiple Columns
Mockito How to Mock Only the Call of a Method of the Superclass
@Autowired - No Qualifying Bean of Type Found for Dependency