0

I want to get the body of the request from the request with getInputStream(). I made a Requestwrapper so that i can cache the request, but it doesnt seem to work as the stream is closed exception comes up anyway when i call getInputStream() or getReader(). What am i doing wrong?

Here is my caller code:

RequestWrapper request = new RequestWrapper(((ServletRequestAttributes) RequestContextHolder
  .currentRequestAttributes())
 .getRequest());

InputStream obj = request.getInputStream(); //**java.io.IOException: Stream closed**

Here is the Request Wrapper class that should cache the request:

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;

public class RequestWrapper extends HttpServletRequestWrapper {
 private ByteArrayOutputStream cachedBytes;

 public RequestWrapper(HttpServletRequest request) {
  super(request);
 }

 @Override
 public ServletInputStream getInputStream() throws IOException {
  if (cachedBytes == null) {
   cacheInputStream();
  }
  System.out.println("cachednotnull");
  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 inputstream which reads the cached request body */
 public class CachedServletInputStream extends ServletInputStream {
  private ByteArrayInputStream input;

  public CachedServletInputStream() {
   /* create a new input stream from the cached request body */
   input = new ByteArrayInputStream(cachedBytes.toByteArray());
  }

  @Override
  public boolean isFinished() {
   return input.available() == 0;
  }

  @Override
  public boolean isReady() {
   return true;
  }

  @Override
  public void setReadListener(ReadListener listener) {
   throw new RuntimeException("Not implemented");
  }

  @Override
  public int read() throws IOException {
   // TODO Auto-generated method stub
   return input.read();
  }
 }
}
Sebin Benjamin
  • 1,758
  • 2
  • 21
  • 45
Daniel Jeney
  • 486
  • 1
  • 5
  • 19
  • 1
    That only works if all the code processing the request is using the *same* `RequestWrapper` instance. Which means that even Spring should use it if you have a `@RequestBody` parameter in your `@Controller` method. Which means that what you're doing should be done in a `Filter`. – Andreas Nov 03 '19 at 13:06
  • 1
    If I guessed right, and you're not doing that from a `Filter`, see e.g. [Http Servlet request lose params from POST body after read it once](https://stackoverflow.com/q/10210645/5221149) – Andreas Nov 03 '19 at 13:09
  • @Andreas Thanks alot, yes that was the problem, using it in my other filter aswell solves it:) – Daniel Jeney Nov 04 '19 at 08:38

0 Answers0