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)
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.
(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.
public HttpServletRequestWrapper(HttpServletRequest request) Constructs a request object wrapping the given request. Throws: java.lang.IllegalArgumentException - if the request is null.
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder. getRequestAttributes()) . getRequest();
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; } }
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 ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With