Spring 4 WebSocket + Tomcat 7.54 异步支持不起作用

5
我正在使用Spring WebSockets和stomp.js创建一个样例聊天应用程序,我使用的是Tomcat 7.54。但是当浏览器发起xhr请求时,应用程序运行时出现了async-supported错误。
服务器信息:Apache Tomcat/7.0.54 Servlet版本:3.0 JSP版本:2.2 Java版本:1.7.0_25
Web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
    <async-supported>true</async-supported>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
    <session-timeout>
        30
    </session-timeout>
</session-config>

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:websocket="http://www.springframework.org/schema/websocket"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>
            </props>
        </property>
    </bean>

    <context:component-scan base-package="hello" />

    <websocket:message-broker application-destination-prefix="/app">
        <websocket:stomp-endpoint path="/hello">
            <websocket:sockjs/>
        </websocket:stomp-endpoint>
        <websocket:simple-broker prefix="/topic"/>
    </websocket:message-broker>

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />

</beans>

错误

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) 
6个回答

7
我猜你没有显示整个web.xml
对于<filter>,也应该配置<async-supported>true</async-supported>更新 嗯,你的问题非常简单:
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>

你应该为所有请求进行映射,而不仅仅是 根目录


我在应用程序中没有使用任何过滤器,这是我的完整web.xml文件。 - Jaspreet Singh
很奇怪。这里是相同的https://dev59.com/LYDaa4cB1Zd3GeqP_RGJ。你的代码中有任何`WebApplicationInitializer`吗?例如Spring Security? - Artem Bilan
不,我没有使用任何WebApplicationInitializer或其他东西, 链接 你可以从上面的链接检查项目。 - Jaspreet Singh
没有使用SockJS,它是如何工作的?您使用的是最新版本的Spring吗? - Artem Bilan
Sockjs也在其中。 我正在使用Spring 4.0.6版本。 您可以从[链接](https://drive.google.com/file/d/0B6G5MBbJgaBNRkViQUJfcy1IVFk/edit?usp=sharing)检查项目及其Jar文件。 - Jaspreet Singh
1
不起作用,仍然存在同样的问题,即使我尝试了两个不同的调度器Servlet,一个使用/,另一个使用/*,但没有成功。 - Jaspreet Singh

3
<async-supported>true</async-supported> 应该在servlet和filter标签中都包含。可以使用以下代码片段作为参考:
<web-app ...>
    ...
    <servlet>
        <servlet-name>instantaction</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:META-INF/spring/web/my-servlet-config.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>

    <servlet-mapping>
        ...
    </servlet-mapping>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <async-supported>true</async-supported>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

1
如果您正在使用反向代理,请在nginx.conf文件中添加以下内容。
  # For WebSocket upgrade header
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

0

我在SpringBoot应用程序中遇到了同样的问题,对我来说,它开始工作了:

1)在过滤器中添加asyncSupported,例如:@WebFilter(urlPatterns="/api-acess/*",asyncSupported = true )

2)在扩展类WebSecurityConfigurerAdapter中添加sameOrigin()支持,例如:http.headers().frameOptions().sameOrigin();

我希望这能帮助其他人。


0

尝试升级您的JDK和Tomcat版本。我也遇到了这个问题,我将JDK从1.7升级到1.8,将Tomcat从7.0.54升级到7.0.75,并解决了这个问题。


0

请确保没有其他注入的组件禁用了异步支持。


细节

我了解到Spring默认带有异步支持。

并且(远程关联)同步日志配置可能会禁用整个服务的异步处理。

具体来说,我的logback集成缺少重要行:

public EmbeddedServletContainerCustomizer containerCustomizer(
    final String logbackAccessClasspathConfig
) {
    return container -> {
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            ((TomcatEmbeddedServletContainerFactory) container)
                .addContextCustomizers(context -> {
                    LogbackValve logbackValve = new LogbackValve();
                    logbackValve.setFilename(logbackAccessClasspathConfig);

                    // IMPORTANT:
                    logbackValve.setAsyncSupported(true);

                    context.getPipeline().addValve(logbackValve);
                }
            );
        }
    };
}

感谢其他答案:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接