获取HttpServletRequest状态以避免IllegalStateException

时间:2013-12-10 14:13:58

标签: java servlets web illegalstateexception

有时,来自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]

2 个答案:

答案 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)作为已提交的响应通常会被关闭,但这不是确定的 - 它可以被关闭但不会被提交。