Spring Async DeferredResult在Tomcat 8中不起作用
我使用Spring 4.0.5和Servlet API 3.1.0创建了一个异步MVC应用程序。 使用Firefox 24,异步行为在Jetty 8.0中运行良好,但我无法在Tomcat 8.0和Firefox 24中使用它。我正在使用DeferredResult来管理异步请求。 知道我错过了什么吗? 它可能是一些Tomcat设置或web.xml中的某些内容,因为完全相同的Java代码在Jetty中运行良好。
当异步请求最终有结果并且应该写入响应时,我看到记录了以下消息:
WebAsyncManager - Dispatching request to resume processing RequestResponseBodyMethodProcessor - Written [true] as "application/json" using MappingJacksonHttpMessageConvertor DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'app': assuming HandlerAdapter completed request handling DispatcherServlet - Successfully completed request
长时间运行的请求永远不会回到我的浏览器,最终我在Tomcat日志中看到这个超时错误:
CoyoteAdapter.asyncDispatch Exception while processing an asynchronous request java.lang.IllegalStateException: Calling [asyncTimeout()] is not valid for a request with Async state [Dispatching]
–server.xml–
–Tomcat web.xml–
default org.apache.catalina.servlets.DefaultServlet debug 0 listings false 1 true jsp org.apache.jasper.servlet.JspServlet fork false xpoweredBy false 3 true default / jsp *.jsp *.jspx
–Spring web-app web.xml–
org.springframework.web.context.ContextLoaderListener webAppRootKey my-async-app contextConfigLocation classpath:spring/app-config.xml app org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring/controllers-config.xml 1 true app /app/*
此问题与此处和此处描述的Tomcat中的错误有关。
可能的解决方案:
- 使用更稳定的Tomcat版本,例如已修复此错误的Tomcat 7.0.47。
- 使用更高级的调度程序,例如org.springframework.web.servlet.DispatcherServlet
-
按照此处的建议覆盖HttpServlet:
public class AsyncServlet extends HttpServlet { protected void doGet(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (request.isAsyncStarted()) { response.getWriter().write("asyncResult=" + request.getAttribute("asyncResult")); } else { final AsyncContext asyncContext = request.startAsync(request, response); asyncContext.addListener(new AsyncListener() { public void onTimeout(AsyncEvent event) throws IOException { request.setAttribute("asyncResult", "timeout\n"); asyncContext.dispatch(); } public void onStartAsync(AsyncEvent event) throws IOException { } public void onError(AsyncEvent event) throws IOException { } public void onComplete(AsyncEvent event) throws IOException { } }); asyncContext.setTimeout(5000L); } } }