Search code examples
javaspring-bootservletsfilter

Spring HttpServletRequest is empty when already used


At Class A after getting the request body, The Class B is getting empty request body. As per checking if going to comment the code in Class A to retrieve the request body, Class B will able to get the request body.

Is there a way to make HttpServletRequest will not remove the request body in Class A, Inorder Class B can still get the request body?

Class A


@Autowired
        private HttpServletRequest request;
  

 public Authentication authenticate(Authentication authentication) throws AuthenticationException {

 String requestBody =  extractBody(request);
            System.out.println("Request Body1: "+requestBody);

....other codes



}

   public static String extractBody(HttpServletRequest request){
        String body = null;
        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) {
            try {
                throw ex;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    try {
                        throw ex;
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        body = stringBuilder.toString();
        return body;
    }

Class B

  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {

 String requestBody =  extractBody(request);
            System.out.println("Request Body2: "+requestBody);

....other codes

  

}

 public static String extractBody(HttpServletRequest request){
        String body = null;
        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) {
            try {
                throw ex;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    try {
                        throw ex;
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        body = stringBuilder.toString();
        return body;
    }

Solution

  • Request body can be consumed only once from the HttpServletRequest object by default.

    Once you read the request body in Class A, the input stream might be consumed, and subsequent attempts to read it in Class B will result in an empty body.

    To address this issue, you can try:

    • Read the Request Body Once and Cache It: When you read the request body in Class A, store it somewhere (e.g., in a byte array) before processing it. Then, you can pass this cached request body to Class B.
    • Use HttpServletRequestWrapper to Wrap the Request: You can create a custom implementation of HttpServletRequestWrapper that overrides the getInputStream() or getReader() method to return a new stream or reader each time it's called.

    Here is an example: https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times