Reading a Servlet/Spring Request Body Multiple Times

Featured image for sharing metadata for article

I've recently been writing a javax.servlet.Filter to perform validation on a request coming from Netlify's Deploy Notifications and have needed to read the request body to validate that the request is correct.

However, I've found this a little bit painful, as the Java Servlets provide a ServletInputStream that can only be read once, and if you don't, the web server you're using i.e. Spring may reject the incoming request.

This means that your requests will fail with the following/a similar error:

HTTP/1.1 400
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 25 May 2020 15:45:29 GMT
Connection: close
{
    "timestamp": "2020-05-25T15:45:33.739+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Required request body is missing: public org.springframework.http.ResponseEntity<java.lang.String> me.jvt.hacking.controller.Controller.echo(java.lang.String)",
    "path": "/"
}

To avoid this, we need to cache the ServletInputStream, so the web server can read the input, as well as the Filter(s) themselves.

For the sake of this example, I'll create an endpoint that echoes the request body, i.e.

$ curl localhost:8080/ -d 'hi' -H 'content-type: application/json' -i
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2
Date: Mon, 25 May 2020 15:42:16 GMT

hi

And will have a Filter that logs the request body, too.

Complete code can be found at  jamietanna/multiple-read-servlet.

Using ContentCachingRequestWrapper

On paper, using Spring's ContentCachingRequestWrapper should work. It caches content read from the ServletInputStream, and allows easy retrieval.

However, it doesn't take into account the need for the ServletInputStream to be re-read, which means we still receive the HttpMessageNotReadableException exceptions about the request body being missing.

Creating our own class

Following arberg's response on Http Servlet request lose params from POST body after read it once and Marco's response on HttpServletRequestWrapper, example implementation for setReadListener / isFinished / isReady?, I've created the MultiReadHttpServletRequest class which is available in Maven Central:

  <groupId>me.jvt.multireadservlet</groupId>
  <artifactId>multiple-read-servlet</artifactId>
  <version>4.0.1</version> <!-- version mirrors the javax.servlet:javax.servlet-api version -->

And can be found in MultiReadHttpServletRequest.java, with example usage in BodyReadFilter.java.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #java #spring #servlet.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.