Tomcat 7异步处理失败 – 只有一个请求同时处理

我试图使用Servlet API 3中定义的异步处理实现COMET聊天。它无法正常工作 – 聊天被阻止,所以我创建了调试servlet来仅测试异步部分。

这是我的doGet方法:

@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { log.debug("doGet called"); int timeout = 30 + RandomUtils.nextInt(60); String message = RandomStringUtils.randomAlphanumeric(50 + RandomUtils.nextInt(250)); response.setHeader("Access-Control-Allow-Origin", "*"); final AsyncContext context = request.startAsync(); synchronized(items) { items.add(new RequestItem(context, message, timeout)); } log.debug("doGet created request and finished"); } 

我正在将请求项放入队列中,并且有一个线程正在运行,它将在指定的超时后获取项目并向AsyncContext发送响应,打印有关它的消息。 问题是,线程被阻塞,直到AsyncContext得到响应。 这是在浏览器中请求4页加载后在我的日志中可见的内容:

 2011-12-08 13:56:36,923 DEBUG [my.servlet.TestAsyncServlet] doGet called 2011-12-08 13:56:36,952 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished 2011-12-08 13:57:39,934 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@175870a, message=zEQpATavzwFl6qIbBKve4OzIY9UUuZBwbqN1TC5KpU3i8LM9B6ChgUqaRmcT2yF, timeout=0] 2011-12-08 13:57:39,962 DEBUG [my.servlet.TestAsyncServlet] doGet called 2011-12-08 13:57:39,962 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished 2011-12-08 13:58:53,949 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@88ee03, message=pKHKC632CPIk7hGLV0YqCbQl1qpWIoyNv5OWCp21bEqoni1gbY79HT61QEUS2eCjeTMoNEwdqKzCZNGgDngULysSzVdzFTnQQ5cQ8JvcYnp1pLVqGTueJPWnbRdUuO, timeout=0] 2011-12-08 13:58:53,960 DEBUG [my.servlet.TestAsyncServlet] doGet called 2011-12-08 13:58:53,960 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished 2011-12-08 13:59:36,954 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@197950e, message=43FPeEUZWBLqgkAqS3WOFMiHUMVvx6o4jNqWLx8kUvwxqJqpOZyGCtiIcr7yw, timeout=0] 2011-12-08 13:59:36,999 DEBUG [my.servlet.TestAsyncServlet] doGet called 2011-12-08 13:59:36,999 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished 2011-12-08 14:00:34,957 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@1cb1278, message=r69Y4NQsyR1vj0kzUlHssic2x1Yrr6T09IGKjWAH1E6Lz4VhFTy9dQHi5CPeTObyjLLBDlCLEDfiyMUnVkVIEgYG7r47Ak4w30RklhzdEi9nthqdfNkry6nyjircsFPX534NqWjI1LwsrGq5nOa3ZYtfjfPVpGlk4KDmWP11L53YntO3GmptZPKa50gcqj9i, timeout=0] 

正如它所看到的那样,只有在先前的请求(理论上是异步的)被回答之后才会调用下一个doGet方法。 所以整个异步的东西根本不起作用! 这是web.xml声明:

   TestAsyncServlet my.servlet.TestAsyncServlet true   TestAsyncServlet /test-async  

我正在做所有在互联网上找到的。 我没有看到犯错误的地方。 我发现在servlet.xml中配置没什么特别之处。 所以问题是,为什么它不能正常工作?

好吧,作为研究的一部分,我编写了测试程序,它打开了与tomcat的多重连接,并在异步servlet上进行了GET / POST。 我已经调试并重新检查了我的server.xml配置,有限的线程池以便更好地查看测试结果等。现在我的连接器配置如下所示:

  

这是有效的! 我已经使用NIO进行了测试,并且一次建立了1000个连接,并且所有这些连接都在一次完成。

但是,我所描述的效果仍然存在于浏览器中。 当我尝试在10个选项卡上加载servlet时,首先加载,而不是第二个等等。这似乎是浏览器的行为,没有任何东西在服务器上被阻止。 当我打开3个浏览器(Firefox,Chrome,Opera)时,我一次处理了3个连接。

因此,Servlet API 3.0中定义的异步处理适用于Tomcat 7,但是,它必须使用自己的程序进行测试,而不是使用浏览器中的多个选项卡…测试多个选项卡中的COMET聊天也无法按预期工作。 但是,在现实生活中,一台计算机只能打开一个连接。 并且,浏览器的行为不是任何服务器的错。

编辑在将Spring MVC解决方案包含到Web应用程序中之后,停止了异步处理模式(忽略了web.xml中的参数)。 但是,可以通过添加行手动设置异步支持:

 request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true); 

我认为您的服务器配置正确。 如果您只是使用浏览器加载,那么问题可能就是浏览器的工作方式。 如果您只是使用浏览器访问网页,则浏览器将尝试加载整个页面并阻止,直到完成。 在异步请求完成之前,您的浏览器将无法完成加载。

例如,如果您使用像Fiddler这样的工具查看消息,我希望您会看到以下内容(假设延迟为4):

 Browser -> Server [Time: 0] Request Server -> Browser [Time: 0.1] Async Response Server -> Browser [Timer: 4] Complete Response Browser shows page loaded. 

如果你拿出了异步模式,你会看到:

 Browser -> Server [Time: 0] Request Server -> Browser [Time: 4] Response Browser shows page loaded. 

在这两个示例中,在整个请求完成之前,页面将不会完全加载,即使一个是异步的并且一个是同步的。 要充分利用异步请求,您将需要一个更智能的客户端,例如Javascript或flex等。

换句话说,我认为只要加载浏览器就可以说服务器是否正确。 我会抓住像Fiddler这样的工具,看看究竟是什么HTTP消息。