Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read request.getInputStream() multiple times

I have this code:

@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)         throws IOException, ServletException {     logger.info("Filter start...");      HttpServletRequest httpRequest = (HttpServletRequest) request;     HttpServletResponse httpResponse = (HttpServletResponse) response;      String ba = getBaId(getBody(httpRequest));      if (ba == null) {         logger.error("Wrong XML");         httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);     } else {                if (!clients.containsKey(ba)) {             clients.put(ba, 1);             logger.info("Client map : init...");         } else {             clients.put(ba, clients.get(ba).intValue() + 1);             logger.info("Threads for " + ba + " = " + clients.get(ba).toString());         }          chain.doFilter(request, response);     } } 

and this web.xml (packages are shortened and names changed, but it looks the same)

<?xml version="1.0" encoding="ISO-8859-1"?> <web-app>   <filter>     <filter-name>TestFilter</filter-name>     <filter-class>pkg.TestFilter</filter-class>   </filter>   <filter-mapping>     <filter-name>TestFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>    <context-param>     <param-name>contextConfigLocation</param-name>     <param-value>WEB-INF/applicationContext.xml</param-value>   </context-param>    <listener>     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>   </listener>    <servlet>     <servlet-name>Name</servlet-name>     <display-name>Name</display-name>     <servlet-class>pkg.Name</servlet-class>     <load-on-startup>1</load-on-startup>   </servlet>   <servlet-mapping>     <servlet-name>Name</servlet-name>     <url-pattern>/services/*</url-pattern>   </servlet-mapping> </web-app> 

I want to invoke the Servlet after the Filter. I was hoping chain.doFilter(...) could do the trick, but i always get this error on the line with chain.doFilter(...):

java.lang.IllegalStateException: getInputStream() can't be called after getReader() at com.caucho.server.connection.AbstractHttpRequest.getInputStream(AbstractHttpRequest.java:1933) at org.apache.cxf.transport.http.AbstractHTTPDestination.setupMessage(AbstractHTTPDestination.java:249) at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:82) at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:283) at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:166) at org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:174) at org.apache.cxf.transport.servlet.AbstractCXFServlet.doPost(AbstractCXFServlet.java:152) at javax.servlet.http.HttpServlet.service(HttpServlet.java:153) at javax.servlet.http.HttpServlet.service(HttpServlet.java:91) at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:103) at pkg.TestFilter.doFilter(TestFilter.java:102) at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87) at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:187) at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:265) at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:273) at com.caucho.server.port.TcpConnection.run(TcpConnection.java:682) at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:743) at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:662) at java.lang.Thread.run(Thread.java:619) 
like image 785
user219882 Avatar asked Dec 15 '10 10:12

user219882


People also ask

How do you read a request body multiple times?

So how can I retrieve Inputstream / Reader or the request body more than one time? One solution could be to use a ThreadLocal to store params inside a filter from request and then use them anywhere in your code at any number of times.

What is request getInputStream ()?

(0 cow) (0 skulls) request. getInputStream() is used to get the body of the request. Thus, you will only get the body of the request, not the whole thing. the request.

What is HttpServletRequestWrapper in Java?

public HttpServletRequestWrapper(HttpServletRequest request) Constructs a request object wrapping the given request. Throws: java.lang.IllegalArgumentException - if the request is null.

How do I get Servletrequest in spring boot?

HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder. getRequestAttributes()) . getRequest();


2 Answers

Working code based on the accepted answer.

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {  private static final Logger logger = Logger.getLogger(CustomHttpServletRequestWrapper.class); private final String body;  public CustomHttpServletRequestWrapper(HttpServletRequest request) {     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) {           logger.error("Error reading the request body...");       } finally {           if (bufferedReader != null) {               try {                   bufferedReader.close();               } catch (IOException ex) {                   logger.error("Error closing bufferedReader...");               }           }       }        body = stringBuilder.toString();   }  @Override   public ServletInputStream getInputStream () throws IOException {               final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());      ServletInputStream inputStream = new ServletInputStream() {           public int read () throws IOException {               return byteArrayInputStream.read();           }       };      return inputStream;   }  } 
like image 60
user219882 Avatar answered Sep 21 '22 15:09

user219882


You probably start consuming the HttpServletRequest using getReader() in :

String ba = getBaId(getBody(httpRequest));  

Your servlet tries to call getInputStream() on the same request, which is not allowed. What you need to do is use a ServletRequestWrapper to make a copy of the body of the request, so you can read it with multiple methods. I dont have the time to find a complete example right know ... sorry ...

like image 35
Guillaume Avatar answered Sep 22 '22 15:09

Guillaume