Spring Boot启用<async-supported>,如web.xml </async-supported>

时间:2014-10-06 09:09:40

标签: java spring spring-mvc spring-boot

我遇到Spring Boot配置问题。我在一些应该使用套接字的移动设备上遇到例外:

java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
    at org.springframework.util.Assert.isTrue(Assert.java:65)
    at org.springframework.http.server.ServletServerHttpAsyncRequestControl.<init>(ServletServerHttpAsyncRequestControl.java:59)
    at org.springframework.http.server.ServletServerHttpRequest.getAsyncRequestControl(ServletServerHttpRequest.java:202)
    at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.handleInitialRequest(AbstractHttpSockJsSession.java:202)
    at org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.handleRequestInternal(AbstractHttpSendingTransportHandler.java:66)
    at org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.handleRequest(AbstractHttpSendingTransportHandler.java:58)
    at org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService.handleTransportRequest(TransportHandlingSockJsService.java:254)
    at org.springframework.web.socket.sockjs.support.AbstractSockJsService.handleRequest(AbstractSockJsService.java:322)
    at org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler.handleRequest(SockJsHttpRequestHandler.java:88)
    at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:51)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    ...

从异常中可以看出,我必须通过在web.xml文件中添加true来启用异步处理。但这是问题,因为我没有它 - 我们的项目使用Spring Boot。

有没有办法在Spring Boot中提供相同的功能呢?

3 个答案:

答案 0 :(得分:16)

您只需要定义dispatcherServlet @Bean

@Bean
public ServletRegistrationBean dispatcherServlet() {
    ServletRegistrationBean registration = new ServletRegistrationBean(
            new DispatcherServlet(), "/");
    registration.setAsyncSupported(true);
    return registration;
}

它会覆盖DispatcherServletAutoConfiguration中的默认值。

答案 1 :(得分:1)

也许值得一提的是,Spring Boot默认为调度程序servlet和所有过滤器启用了异步支持

来自github的报价:

  

我们自动将async-supported设置为true   因为DispatcherServlet知道如何处理这些请求和   它基本上取决于单个控制器方法来返回一些东西   像DeferredResult一样。此外,我们还设置了异步支持   任何过滤器(通过getServletFilters提供)以及设置   每个过滤器的DispatcherType包含ASYNC。

至少我的做法支持这个陈述

答案 2 :(得分:1)

即使我参加聚会迟到,我仍在为后代发布工作解决方案。

我也遇到过同样的问题,并尝试了@Artem Bilan建议的解决方案。但是在调试代码后,我知道servletRegistrationBean.isAsyncSupported()默认为true

enter image description here

由代码块生成的实际错误是来自方法org.springframework.web.context.request.async.StandardServletAsyncWebRequest.startAsync()的,当getRequest().isAsyncSupported()false时,我们会收到此错误。尽管ServletRegistrationBean#asyncSupported的值为true,但所有API请求的HttpServletRequest#isAsyncSupported()方法值始终设置为false

代码块Code Reference

的执行
Assert.state(getRequest().isAsyncSupported(),
                "Async support must be enabled on a servlet and for all filters involved " +
                "in async request processing. This is done in Java code using the Servlet API " +
                "or by adding \"<async-supported>true</async-supported>\" to servlet and " +
                "filter declarations in web.xml.");

进一步分析时,我知道requestAttributes-> Globals.ASYNC_SUPPORTED_ATTR决定是否必须以异步方式处理请求。

在正常情况下,请求没有Globals.ASYNC_SUPPORTED_ATTR requestAttribute,因此如果我们使用某些内容为所有请求手动将requestAttribute request.asyncSupported值添加为true,则ASYNC_SUPPORTED_ATTR将为false像过滤器一样,然后根据下面的代码块Code Reference

,将request#asyncSupported的值设置为true
specialAttributes.put(Globals.ASYNC_SUPPORTED_ATTR,
                new SpecialAttributeAdapter() {
                    @Override
                    public Object get(Request request, String name) {
                        return request.asyncSupported;
                    }

                    @Override
                    public void set(Request request, String name, Object value) {
                        Boolean oldValue = request.asyncSupported;
                        request.asyncSupported = (Boolean)value;
                        request.notifyAttributeAssigned(name, value, oldValue);
                    }
                });

尽管没有明确的答案,但我已经针对此问题实施了变通方法。要汇总所有必需的更改,请在下面列出:

  1. 添加过滤器以将请求属性设置为request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, true)

@Component
public class AsyncSupportFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, true);
        chain.doFilter(request, response);
    }
}

  1. 将过滤器添加到您的过滤器链中,就我而言,我已将过滤器注册到spring上下文中,如下所示。

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   @Autowired
   private AsyncSupportFilter asyncSupportFilter = null;
   @Override
   public void configure(HttpSecurity httpSecurity) {

       httpSecurity.addFilter(asyncSupportFilter);
       // we can add the filter before any filter like as httpSecurity.addFilterBefore(asyncSupportFilter , BasicAuthenticationFilter.class);
   }
}