【问题标题】:Spring Boot enable <async-supported> like in web.xmlSpring Boot 启用 <async-supported> 就像在 web.xml 中一样
【发布时间】:2014-11-30 12:36:03
【问题描述】:

我的 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 中提供相同的功能?

【问题讨论】:

    标签: java spring spring-mvc spring-boot


    【解决方案1】:

    我的解决方案:

    @WebFilter(value = {"/subscriberinfo/query/single/*"})
    public class ...Filter{
    } 
    

    到

    @WebFilter(value = {"/subscriberinfo/query/single/*"}, asyncSupported = true)
    public class ...Filter{
    } 
    

    【讨论】:

      【解决方案2】:

      即使我迟到了,我也会为后代发布我的工作解决方案。

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

      .

      代码块产生的实际错误来自方法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,因此 request.asyncSupported 将为 false,如果我们手动将 requestAttribute ASYNC_SUPPORTED_ATTR 值添加为 true,则使用过滤器之类的所有请求然后 request#asyncSupported根据下面的代码块Code Reference,值将设置为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. 将过滤器添加到您的过滤器链中,在我的情况下,我已将过滤器注册到弹簧上下文中,如下所示。
      
      @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);
         }
      }
      

      【讨论】:

      • 我使用了这个过滤器,它解决了我的问题。请注意,我没有将过滤器添加到过滤器链中。 Spring 会自动处理。
      【解决方案3】:

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

      引用github:

      我们自动将 async-supported 设置为 true 因为 DispatcherServlet 知道如何处理此类请求,并且 基本上取决于各个控制器方法来返回某些东西 就像一个 DeferredResult。此外,我们还为 任何过滤器(通过 getServletFilters 提供)以及设置 每个过滤器的 DispatcherType 都包含 ASYNC。

      至少我的实践支持这种说法

      【讨论】:

      • 这种做法是否包括在 tomcat 上部署 Spring 应用程序而不是独立应用程序?
      • @Antoniossss 我的回答是在将单体式 spring(不是 spring boot)应用程序迁移到一组独立的 spring boot 服务的项目中做出的。据我记得,以前的单片非 Spring Boot 版本的应用程序必须显式打开异步支持。
      • 事实证明这不是真的。
      • Spring Boot 中的行为发生了变化?上述声明是 Spring Boot 作者在 2014 年发表的.....
      • 我也这么说,但我也这么说,但它只是不起作用。我们不得不在某个地方加上 @EnableAsync 之类的东西 - 记不清了,但这是一个单一注释的问题(乍一看与此无关)
      【解决方案4】:

      你只需要定义dispatcherServlet@Bean:

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

      它会覆盖 DispatcherServletAutoConfiguration 中的默认值。

      【讨论】:

        猜你喜欢
        • 2016-08-12
        • 2015-12-24
        • 2017-08-27
        • 1970-01-01
        • 2015-03-29
        • 1970-01-01
        • 2017-08-30
        • 2012-03-18
        • 1970-01-01
        相关资源
        最近更新 更多