通过Java客户端使用Spring 4实现的WebSockets连接到Stomp

Kir*_* S. 19 tomcat stomp websocket spring-websocket java-websocket

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

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) { ... });
....
Run Code Online (Sandbox Code Playgroud)

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

StompConnection connection = new StompConnection();
connection.open("host", port);
connection.connect(new HashMap<String, String>());
Run Code Online (Sandbox Code Playgroud)

如果我指定port61613,连接成功,但我直接打了RabbitMQ,而不是我的服务器(这不是我想要的).如果我指定8080(或80),在连接时我得到一个错误

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

和跟踪显示这是因为CONNECT帧永远不会收到预期的CONNECTED帧(事实上,它不会收到任何回复).

所以我很困惑:我使用了错误的端口吗?或处理一些库不兼容?或者我是否需要以某种方式指示Tomcat我想要将HTTP连接升级到WebSockets

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

Kir*_* S. 1

当我找到答案时我应该发布答案。为了实现 Java 客户端,连接到 Tomcat,而不是直接连接到 RabbitMQ,Java 客户端不仅应该实现 STOMP Over WebSockets,还应该实现开放握手

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

我尝试使用的库只是缺少此功能。他们尝试直接进行WebSocket连接而不需要握手。

所以回答我自己的问题:

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

我最终使用了Spring WebSocket 库,它可以轻松实现这一切。这是最简单的设置:

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.
Run Code Online (Sandbox Code Playgroud)

另请参阅Spring 参考中的 WebSocket 支持部分