Comment lire demande.getInputStream() plusieurs fois
J'ai ce 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);
}
}
et ce web.xml (les paquets sont raccourcies et les noms ont été changés, mais il a la même apparence)
<?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>
Je veux invoquer la Servlet après le Filtre. J'espérais chain.doFilter(...)
pourrait faire l'affaire, mais j'ai toujours cette erreur sur la ligne avec 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)
- Oui, cela devrait fonctionner. Le servlet de travail, sans le filtre?
- La servlet fonctionne sans le filtre et le filtre sans
chain.doFilter()
travaille trop - de le mettre à l'extérieur de if..else n'a pas aider
- Aussi, je remarque que vous essayez de lire les données XML à l'aide d'un Lecteur, qui, dans mon expérience, est généralement faux. Vous devriez être en utilisant un analyseur XML sur un InputStream. J'espère bien que vous n'êtes pas en tirant des valeurs de données XML à l'aide d'expressions régulières ou quelque chose comme ça? Pouvons-nous voir votre getBaId() et getBody() méthodes?
- J'ai besoin d'un seul paramètre et je pense que les expressions régulières peut être plus rapide et plus efficace que l'analyse de l'ensemble de XML.
Vous devez vous connecter pour publier un commentaire.
Vous avez probablement commencer à consommer de la HttpServletRequest à l'aide de
getReader()
dans :Votre servlet essaie de l'appeler
getInputStream()
sur la même demande, qui n'est pas autorisé. Ce que vous devez faire est d'utiliser unServletRequestWrapper
pour faire une copie de la corps de la demande, de sorte que vous pouvez le lire avec plusieurs méthodes. Je n'ai pas le temps de trouver un exemple complet droit de savoir ... désolé ...getReader()
ne l'aide pas. L'exception seragetReader() has already been called for this request
Code de travail basé sur la accepté de répondre.
getReader()
trop:public BufferedReader getReader() throws IOException { return new BufferedReader(new StringReader(body)); }
Cela a fonctionné pour moi. Il met en œuvre
getInputStream
.Alors que vous utilisez dans votre méthode:
Pour Servlet 3.1
setReadListener
vous-même.inputStream dans le servlet demande ne peut être utilisée qu'une fois en raison de son flux,vous pouvez l'enregistrer et puis l'obtenir à partir d'un tableau d'octets,cela peut résoudre.
dans le filtre:
demande.getInputStream() est autorisé à lire qu'une seule fois. Afin d'utiliser cette méthode plusieurs fois, nous avons besoin de faire supplémentaire de la tâche personnalisée pour HttpServletReqeustWrapper classe. voir mon exemple de classe wrapper ci-dessous.
Dans mon cas, je faire le suivi de toutes les demandes entrantes dans le journal. J'ai créé un Filtre
public class TracerRequestFilter implémente Filtre {
private static final de l'Enregistreur de JOURNAL = LoggerFactory.getLogger(TracerRequestFilter.class);
Il fonctionne pour moi Servlet 2.5 et 3.0. Je vois une demande tous les paramètres à la fois la forme codée et demande json corps.