首页 文章

获取HttpServletRequest状态以避免IllegalStateException

提问于
浏览
0

有时,来自 HttpServletRequest 的方法 req.startAsync() 会抛出 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 ERROR [org.apache.catalina.core.ContainerBase . [jboss.web] . [default-host] . [/ esus] . [LongPollServlet]](http- / 0.0.0.0:8080-2 )JBWEB000236:servlet LongPollServlet的Servlet.service()抛出异常:java.lang.IllegalStateException:JBWEB000049:响应已经在org.apache.catalina.connector.Request.startAsync(Request.java:3180)已关闭[jbossweb-7.2 org.apache.catalina.connector.Request.startAsync(Request.java:3170)中的.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] [jbossweb-7.2.0.Final-redhat -1.jar:7.2.0.Final-redhat-1]在org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:925)[jbossweb-7.2.0.Final-redhat-1.jar:7.2 com.performer.framework.server.LongPollServlet.continueDoPost(LongPollServlet.java:75)[st10.framework.webserver.jar:] com.performer.framework.server.LongPollServlet.doPost上的.0.Final-redhat-1] (LongPollServlet.java:62)[st10.framework.webserver.jar:]在javax.servlet.http.HttpServlet.service(HttpServlet.java:754)[jboss-servl et-api_3.0_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1],位于javax.servlet.http.HttpServlet.service(HttpServlet.java:847)[jboss-servlet- api_3.0_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1]在org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295)[jbossweb-7.2 . 0.Final-redhat-1.jar:7.2.0.Final-redhat-1] org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)[jbossweb-7.2.0.Final-redhat- 1.jar:7.2.0.Final-redhat-1]在org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)[jbossweb-7.2.0.Final-redhat-1.jar:7.2 . 0.Final-redhat-1]在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]在org.jboss.as.jpa.interceptor.WebNonTxEmCloserV alve.invoke(WebNonTxEmCloserValve.java:50)[jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]在org.jboss.as.web.security . 在org.apache.catalina.core.StandardHostValve中的SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)[jboss-as-web-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8] . 在org.apache.catalina.valves.ErrorReportValve.invoke中调用(StandardHostValve.java:145)[jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1](ErrorReportValve.java: 97)[jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)[jbossweb-7.2 .0.Final-redhat-1.jar:7.2.0.Final-redhat-1]在org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336)[jbossweb-7.2.0.Final-redhat -1.jar:7.2.0.Final-redhat-1]在org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)[jbossweb-7.2.0.Final-redhat-1.jar:7.2 .0.Final-redhat-1]在org.apache.coyote.http11.Http11Pro tocol $ Http11ConnectionHandler.process(Http11Protocol.java:653)[jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] atg.apache.tomcat.util.net.JIoEndpoint $ java.lang.Thread.run中的Worker.run(JIoEndpoint.java:915) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1] [rt . jar :1.6.0_34]

2 回答

  • 1

    根据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)
    
  • 2

    您想要检查响应,而不是请求状态,因为 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)作为提交的响应通常会被关闭,但这不是确定的 - 它可以被关闭但不会被提交 .

相关问题