有时,来自req.startAsync()
的方法HttpServletRequest
会抛出IllegalStateException
(响应已经关闭)。
如何检查请求状态以避免IllegalStateException
?
req.isAsyncSupported()
始终返回true。
相关代码:
final HttpSession httpSession = req.getSession(false);
if (httpSession == null) {
resp.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return;
}
final AsyncContext asynContext = req.startAsync(); //exception here`
例外:
12:28:12,735错误 [org.apache.catalina.core.ContainerBase [jboss.web] [缺省主机]。[/ esus]。[LongPollServlet]] (http- / 0.0.0.0:8080-2)JBWEB000236:servlet的Servlet.service() LongPollServlet抛出异常:java.lang.IllegalStateException: JBWEB000049:响应已经关闭 org.apache.catalina.connector.Request.startAsync(Request.java:3180) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.connector.Request.startAsync(Request.java:3170) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:925) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at com.performer.framework.server.LongPollServlet.continueDoPost(LongPollServlet.java:75) [st10.framework.webserver.jar:] at com.performer.framework.server.LongPollServlet.doPost(LongPollServlet.java:62) [st10.framework.webserver.jar:] at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) [JBoss的-servlet的api_3.0_spec-1.0.2.Final-红帽-1.jar:1.0.2.Final-红帽-1] 在javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [JBoss的-servlet的api_3.0_spec-1.0.2.Final-红帽-1.jar:1.0.2.Final-红帽-1] 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169) [jboss-as-web-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java:653) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:915) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] at java.lang.Thread.run(Unknown Source)[rt.jar:1.6.0_34]
答案 0 :(得分:2)
根据startAsync()的文档:
抛出:IllegalStateException - 如果此请求在范围内 不支持异步操作的过滤器或servlet (即,isAsyncSupported()返回false),或者如果此方法是 在没有任何异步调度的情况下再次调用(由其中一个调用 AsyncContext #dispatch方法),在任何范围之外调用 这种调度,或在同一范围内再次调用 发送,或者响应已经关闭。
似乎Tomcat已将isAsyncSupported()
设置为true
。
您可以将HttpServletRequest
对象中的async属性设置为true
:
req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
或
((org.apache.catalina.connector.Request)req).setAsyncSupported(true);
您还必须在servlet前面添加:
@WebServlet(... , asyncSupported = true)
答案 1 :(得分:1)
您想检查响应,而不是请求状态,因为原始响应关闭时无法调用startAsync()
。
您应该能够从代码中看到关闭响应的位置(例如,如果它在某处调用response.close();
)。你应该在此之前调用startAsync()
,或者在调用之后设置一个标志,并在调用startAsync()
之前检查它。
如果您根本没有处理响应,可以尝试测试HttpServletResponse
以查看它是否已关闭,但没有明确的方法:
if (!isClosed(response.getOutputStream())) {
startAsync();
// ...
有关isClosed()
的实施的讨论,请参阅this answer。没有简单或推荐的方法,但是如果你是绝望的,这可能有用(未经测试),但它会写入响应输出流,这很危险:
boolean isClosed(ServletOutputStream sos) {
try {
os.println(""); // This will append extra line feed to the HTTP response!
return false;
} catch(IOException e) {
return true; // assume due to stream being closed
}
}
或者,您可以依赖response.isCommitted()
(see doc)作为已提交的响应通常会被关闭,但这不是确定的 - 它可以被关闭但不会被提交。