【问题标题】:Spring Websockets 4.1.6 with Tomcat 7.0.54 and Apache 2.4带有 Tomcat 7.0.54 和 Apache 2.4 的 Spring Websockets 4.1.6
【发布时间】:2015-05-12 08:51:03
【问题描述】:

我在运行一个使用 Spring WebSockets 4.1.6、Tomcat 7.0.54 和 Apache 2.4.16 作为 Web 服务器的简单应用程序时遇到了一些麻烦。

我在互联网上阅读了很多帖子,但我不知道发生了什么。服务器启动没有问题。我在我的服务器项目中发布了一个 index.html,它启动了一个 WebSocket 连接。

如果我直接从 Tomcat 访问这个文件,它可以完美运行。

http://localhost:8080/myserver/messaging/index.html

但是如果我从 Apache 服务器访问这个文件,它就不起作用了。

http://localhost/messages/messaging/index.html

在我的 Apache 服务器中,我配置了代理通道:

ProxyPass           /messages http://localhost:8080/myserver
ProxyPassReverse    /messages http://localhost:8080/myserver

我的服务器 WebSocket 配置如下:

@Configuration
@EnableWebSocketMessageBroker
public class PuiWebSocketConfig extends
    AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.setApplicationDestinationPrefixes("/app");
        config.enableSimpleBroker("/user", "/topic");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/puimessaging").withSockJS();
    }
}

我的客户按如下方式进行连接:

function connect() {
    var socket = new SockJS('/server/puimessaging');
    var stompClient = Stomp.over(socket);
    var headers = {
        puiSessionId : 'a1234567890z'
    };
    stompClient.connect(headers, function(frame) {
        setConnected(true);
        stompClient.subscribe('/user/a1234567890z/response', function(data) {
            ...
        });
    });
}

服务器抛出一个错误,说我需要启用异步支持,但我不知道该怎么做。

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

我尝试在我的 web.xml 文件中添加该属性,但它不起作用:

<servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

<servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

有什么想法吗?

提前致谢。

马克

【问题讨论】:

  • 你更换了你的tomcat连接器吗??这是使用 Websockets、非阻塞 IO 所必需的。
  • 很抱歉,顺便说一句,您的 web.xml 在哪里,您是否将 web.xml 标记为使用 servlet 3.0 并使用 true 。像这样的东西:pastebin.com/RYfEnp4m
  • 拜托,你能再粘贴一下连接器的尖端吗?我认为答案已被删除...谢谢!
  • 我已经删除了它,因为你说它没有帮助。我现在已经取消删除了。
  • 我让它工作了,但不是 100%...我建立了一个包含所有消息支持的独立战争,以及另一个与主应用程序的战争。当我打开客户端时,WebSocket 已正确初始化,但 Apache 无法为我提供很多本地文件......我有很多 HTTP 错误,说文件 XXX 不存在,但它们存在时。跨度>

标签: apache spring-mvc tomcat spring-websocket spring-messaging


【解决方案1】:

我让它工作了,不是通过 WebSockets,而是通过 xhr_streaming。我的配置如下:

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="webApp" 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"
    version="3.0">

    <servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring-mvc</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <async-supported>true</async-supported>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Tomcat (server.xml):

<Connector URIEncoding="UTF-8" connectionTimeout="20000"
        port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
        redirectPort="8443" />

Apache httpd:

...
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_express_module modules/mod_proxy_express.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
# LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
...
ProxyPass   /pideweb-gijon  http://localhost:8080/pideweb_gijon
ProxyPassReverse    /pideweb-gijon  http://localhost:8080/pideweb_gijon
ProxyPass   /pideweb-gijon/endpointpuisocket/   ws://localhost:8080/pideweb_gijon/endpointpuisocket/
ProxyPassReverse    /pideweb-gijon/endpointpuisocket/   ws://localhost:8080/pideweb_gijon/endpointpuisocket/

弹簧配置:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Autowired
    private WebSocketService websocketService;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.setApplicationDestinationPrefixes("/app");
        config.enableSimpleBroker("/user", "/topic");
        // config.setUserDestinationPrefix("/user");
        // config.enableSimpleBroker("/queue", "/topic");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/endpointpuisocket").withSockJS();
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        ChannelInterceptorAdapter interceptor = new ChannelInterceptorAdapter() {

            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                // store or remove the Session ID in the list depending on the
                // message is for Connecting or Disconnecting
                StompHeaderAccessor accessor = StompHeaderAccessor
                        .wrap(message);
                StompCommand command = accessor.getCommand();
                List<String> headersSessionId = accessor
                        .getNativeHeader("puiSessionId");
                if (!CollectionUtils.isEmpty(headersSessionId)) {
                    String sessionId = headersSessionId.get(0);

                    switch (command) {
                    case CONNECT:
                        // add the session ID
                        websocketService.addSession(sessionId);
                        break;
                    case DISCONNECT:
                        // remove the session ID
                        websocketService.removeSession(sessionId);
                        break;
                    default:
                        break;
                    }
                }

                return message;
            }
        };
        registration.setInterceptors(interceptor);
    }

}

Javascript 客户端:

function(gst) {
    var url = '/pideweb-gijon/endpointpuisocket';
    var socket = new SockJS(url);
    var stompClient = Stomp.over(socket);
    var headers = {
        puiSessionId : gst
    };

    var self = this;
    stompClient.connect(headers, function(frame) {
        console.log('Connected: ' + frame);
        self.stompClient.subscribe('/user/' + gst + '/response', function(data) {
            console.log(data.body);
        });
    });
};

这样,当我进入客户端时,会自动尝试连接到服务器。我正在使用 Chrome,这是请求堆栈:

信息请求

Websocket 请求

XHR_streaming 请求

有人知道 Websocket 请求会发生什么吗?

谢谢!

【讨论】:

    【解决方案2】:

    为此,您需要更新您的 tomcat 连接器,进入您的 tomcat 目录 --> conf --> server.xml。找到以下行:

    <Connector connectionTimeout="20000" maxThreads="1000" port="8080" protocol="org.apache.coyote.http1.1"/> 
    

    应该是类似的东西,注意协议,并将其更改为:

    <Connector connectionTimeout="20000" maxThreads="1000" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"/>
    

    重启你的tomcat。

    【讨论】:

      【解决方案3】:

      知道 Tomcat 一切正常,您的 Apache 配置可能有问题。

      Apache默认不支持websocket UPGRADE,需要安装+配置mod_proxy_wstunnel

      如果您希望各种 SockJS 传输正常工作,您可能必须确保 mod_proxy 处于 HTTP 模式(即不是 AJP)并且正确支持 HTTP 持久连接。

      【讨论】:

      • 我启用了这个模块,但它不起作用。如何检查 mod_proxy 是否处于 HTTP 模式并配置连接器?谢谢...
      • 这没有反映在您的问题中;实际上,必须阅读您的问题和所有 cmets 才能尝试猜测您的实际设置是什么。您能否复制/粘贴整个 apache mod_proxy* 配置(加载模块和配置语句)
      • 对不起,布莱恩,我已经发布了所有详细配置的答案。如果你能帮上忙,我会感谢你的。
      【解决方案4】:

      我遇到了同样的问题,@Marc Gil Sendra 的解决方案对我有用。 需要从 Apache 为 WebSocket 协议配置 Proxypass。

      ProxyPass /pideweb-gijon/endpointpuisocket/ws://localhost:8080/pideweb_gijon/endpointpuisocket/

      ProxyPassReverse /pideweb-gijon/endpointpuisocket/ws://localhost:8080/pideweb_gijon/endpointpuisocket/

      我在 Bitnami EC2 (Apache + Tomcat) 中测试过,配置如下 文件配置:/opt/bitnami/apache-tomcat/conf/apache-tomcat-prefix.conf

      <Location /AppContext/endpointpuisocket> ProxyPass ws://localhost:8080/AppContext/endpointpuisocket </Location>

      【讨论】:

      • 嗨!你知道通过 websockets 而不是 xhr_streaming 让它工作吗?谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-12
      • 1970-01-01
      • 2015-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多