【问题标题】:Connecting to Stomp over WebSockets implemented using Spring 4 from Java client从 Java 客户端连接到使用 Spring 4 实现的 WebSockets 上的 Stomp
【发布时间】:2023-09-17 15:27:01
【问题描述】:

我收到了一个 Web 应用程序,它使用 Spring 使用 STOMP over WebSockets Messaging 实现,类似于here 中描述的内容(在后端使用 RabbitMQ)。它在 Tomcat 上运行,我可以使用常规 URL(例如http://host/server/)连接到应用程序。我还得到了一个演示客户端——一个使用 Modernizr WebSockets 和 SockJS 的 JSPX 页面。演示客户端中的连接代码如下所示:

if (Modernizr.websockets) {
    socket = new WebSocket('ws://host/server/endpointx');
}
else {
    socket = new SockJS('/server/endpointy');
}

stompClient = Stomp.over(socket);
stompClient.connect(headers, function(frame) { ... });
....

演示客户端工作正常(当我在浏览器中加载 JSPX 页面时,我可以连接到服务器)。但我的目标是使用一些 Java STOMP 库连接到同一台服务器。问题是,我尝试的库需要 hostport 作为连接参数:例如 ActiveMQ Stomp library:

StompConnection connection = new StompConnection();
connection.open("host", port);
connection.connect(new HashMap<String, String>());

如果我将port 指定为61613,则连接成功,但我直接点击了RabbitMQ,而不是我的服务器(这不是我想要的)。如果我指定8080(或80),在连接时会出现错误

java.io.EOFException 在 java.io.DataInputStream.readByte(未知来源) 在 org.apache.activemq.transport.stomp.StompWireFormat.unmarshal(StompWireFormat.java:137) 在 org.apache.activemq.transport.stomp.StompConnection.receive(StompConnection.java:77) 在 org.apache.activemq.transport.stomp.StompConnection.receive(StompConnection.java:68) 在 org.apache.activemq.transport.stomp.StompConnection.connect(StompConnection.java:139) 在 ....stomp.impl.activemq.ActiveMQStompDriver.connect(ActiveMQStompDriver.java:39) ... 25 更多

跟踪显示这是因为CONNECT 帧从未收到预期的CONNECTED 帧(事实上,它没有收到任何返回)。

所以我很困惑:我是否使用了错误的端口?或处理一些库不兼容?还是我需要以某种方式表明我想要upgrade HTTP connection to WebSockets 的Tomcat?

如果上面的问题很难回答,那么这个问题同样有用:我如何使用 Java 通过在 Tomcat 上运行的 WebSockets 消息通道上的 STOMP 连接到 Spring 应用程序?

【问题讨论】:

    标签: tomcat websocket stomp spring-websocket java-websocket


    【解决方案1】:

    我应该在找到答案时发布答案。 为了实现Java客户端,连接Tomcat,而不是直接连接RabbitMQ,Java客户端不仅要实现STOMP Over WebSockets,还要an opening handshake

    打开握手旨在与基于 HTTP 的兼容 服务器端软件和中介,这样单个端口就可以 由与该服务器和 WebSocket 通信的 HTTP 客户端使用 客户端与该服务器交谈。为此,WebSocket 客户端的 握手是一个 HTTP 升级请求

    我尝试使用的库只是缺少此功能。他们试图在没有握手的情况下直接执行 WebSocket 连接。

    所以回答我自己的问题:

    • 库必须支持打开握手
    • 对于主机和端口,您需要指定 Tomcat 的主机(与 RabbitMQ 不同)和 web 端口(例如 8080),而不是 RabbitMQ 端口

    我最终使用了Spring WebSocket library,这很容易实现。这是最简单的设置:

    taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(N); // N = number of threads
    taskScheduler.afterPropertiesSet();
    
    stompClient = new WebSocketStompClient(new StandardWebSocketClient());
    stompClient.setTaskScheduler(taskScheduler);
    stompClient.setMessageConverter(new MappingJackson2MessageConverter()); 
    
    WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders(); // you can add additional headers here for Tomcat
    
    // Here's the main piece other libraries were missing:
    // The following request will perform both, handshake and connection
    // hence it gets both sets of headers (for Tomcat and for Stomp)
    ListenableFuture<StompSession> future = stompClient.connect(
                url,
                handshakeHeaders,
                new StompHeaders(),
                new CustomStompSessionHandlerAdapter(this)); // called from class that also was implementing CustomStompSessionHandlerAdapter, but this could be separate class as well.
    

    另见WebSocket Support section in Spring reference

    【讨论】:

      最近更新 更多