有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java获取HttpServletRequest状态以避免IllegalStateException

有时来自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.service() for servlet LongPollServlet threw exception: java.lang.IllegalStateException: JBWEB000049: Response has been closed already at 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-redhat-1.jar:1.0.2.Final-redhat-1] at 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] at 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) 个答案

  1. # 1 楼答案

    根据startAsync()的文件:

    Throws: IllegalStateException - if this request is within the scope of a filter or servlet that does not support asynchronous operations (that is, isAsyncSupported() returns false), or if this method is called again without any asynchronous dispatch (resulting from one of the AsyncContext#dispatch methods), is called outside the scope of any such dispatch, or is called again within the scope of the same dispatch, or if the response has already been closed.

    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. # 2 楼答案

    您希望检查响应,而不是请求状态,因为原始响应关闭时无法调用startAsync()

    您应该能够从代码中看到is关闭响应的位置(例如,如果它在某处调用response.close();)。您应该在这一点之前调用startAsync(),或者在调用startAsync()之前设置一个标志并检查它

    如果根本不处理响应,可以尝试测试HttpServletResponse,看看它是否已关闭,但没有明确的方法:

    if (!isClosed(response.getOutputStream())) {
      startAsync();
      // ...
    

    有关isClosed()实现的讨论,请参见this answer。没有简单或推荐的方法,但如果您正在进行desparate,这可能会起作用(未经测试),但它会写入响应输出流,这很危险:

    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),因为提交的响应通常是关闭的,但这并不确定——它可以关闭,但不能提交