Spring Boot 启用 <async-supported> 就像在 web.xml 中一样

问题描述 投票:0回答:4

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)
    ...

正如我从异常中看到的那样,我必须通过将 true 添加到 web.xml 文件来启用异步处理。但这是问题所在,因为我没有它——我们的项目使用 Spring Boot。

有什么方法可以在 Spring Boot 中提供相同的功能吗?

java spring spring-mvc spring-boot
4个回答
16
投票

你只需要定义

dispatcherServlet
@Bean

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

它覆盖了

DispatcherServletAutoConfiguration
中的默认值。


2
投票

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

引自github

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

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


2
投票

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

我遇到了同样的问题并尝试了@Artem Bilan 建议的解决方案。但是调试代码后,我才知道

servletRegistrationBean.isAsyncSupported()
默认是
true
.

.

代码块生成的实际错误来自方法

org.springframework.web.context.request.async.StandardServletAsyncWebRequest.startAsync()
,当
getRequest().isAsyncSupported()
false
时我们会收到此错误。尽管
ServletRegistrationBean#asyncSupported
值为
true
,但对于所有 API 请求,
HttpServletRequest#isAsyncSupported()
方法值始终设置为
false

代码块摘录代码参考

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
将为假,如果我们使用过滤器之类的东西手动添加该 requestAttribute
ASYNC_SUPPORTED_ATTR
值作为真,那么
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. 将过滤器添加到您的过滤器链中,在我的例子中,我已经将我的过滤器注册到 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);
   }
}

0
投票

我的解决方案:

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

@WebFilter(value = {"/subscriberinfo/query/single/*"}, asyncSupported = true)
public class ...Filter{
} 
© www.soinside.com 2019 - 2024. All rights reserved.