I have been struggling with this for at least two weeks now. I'm pretty new to websockets. I have good experience with rest endpoints.
My use case is simple. Client initiates a websocket connection sending some info to server, and server uses that info and, sends client some info back at some regular interval say every 5 seconds. I followed the tutorial here - https://spring.io/guides/gs/messaging-stomp-websocket/ It works perfectly as explained. As per the above tutorial, client initiates a http request, which gets upgraded to websocket.
In my case front end is an angular 10 application, and the front end developer prefers to use rxjs/websocket
and doesn't want to use SockJS client
, as he is sure we don't have to support any legacy browsers, and this is where I'm struck.
Apparently rxjs/websocket
needs url in ws://
protocol.
From the following snippet, I thought my equivalent ws protocol would be
ws://localhost:8080/test
However, it doesn't seem to work. I'm not sure what is wrong. Any help is greatly appreciated!
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer
{
@Override
public void configureMessageBroker(MessageBrokerRegistry config)
{
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/ws/");
@Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
registry.addEndpoint("/test");
}
}
From the tutorial, I changed app.js
, as follows to test this out.
function connect() {
// var socket = new SockJS('http://localhost:8080/test'); This works perfectly
// stompClient = Stomp.over(socket);
ws = new WebSocket('ws://localhost:8080/test');
stompClient = Stomp.client(ws);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/' + $("#site").val(), function (message) {
showMessageSentFromServer(JSON.stringify(message.body));
});
});
}
When I open up the developer tool of chrome and inspect, I see the websocket connection has be established and upgraded or that is what I see. However, in the console, I see an error log as follows. I'm not sure what is wrong.
Screen shot of network:
Console failure log:
stomp.min.js:8 Uncaught DOMException: Failed to construct 'WebSocket': The URL '[object WebSocket]' is invalid.
at Object.client (http://localhost:8080/webjars/stomp-websocket/stomp.min.js:8:7229)
at connect (http://localhost:8080/app.js:18:25)
at HTMLButtonElement.<anonymous> (http://localhost:8080/app.js:54:9)
at HTMLButtonElement.dispatch (http://localhost:8080/webjars/jquery/jquery.min.js:3:10315)
at HTMLButtonElement.q.handle (http://localhost:8080/webjars/jquery/jquery.min.js:3:8342)
Now long story short, I managed to disable SockJs on the server side, by removing withSockJS()
. So what is my equivalent ws
protocol URL?
Also, another challenge I have apart from this is, how do I set up a scheduled process that can send messages to a websocket topic that the client has subscribed, based on the input from the client. I know it is easy to set up a scheduled process using a @Scheduled
annotation. But in my case, I wanted some inputs from the client which is required inside the scheduled process.
Also, please share any resources or examples that you have that explains how to implement a websocket stomp client subscription to a topic using rxjs
I was able to fix the problem by making two simple changes.
ws
and http
protocols by adding two endpoints to the WebSocketConfig
as shown below - one with and the other one without sockjs
as shown below, which made my backend more flexible in terms of supporting both the protocols to establish websocket
connection. I don't know why this wasn't mentioned anywhere in spring docs or else. Perhaps, people thought it is implied!@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer
{
@Override
public void configureMessageBroker(MessageBrokerRegistry config)
{
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/ws/");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
registry.addEndpoint("/test"); // This will allow you to use ws://localhost:8080/test to establish websocket connection
registry.addEndpoint("/test").withSockJS(); // This will allow you to use http://localhost:8080/test to establish websocket connection
}
}
@arturgrzesiak
in previous comment, there was an error in the parameter passed to the Stomp.client(url)
I was silly and passing ws
object instead of plain url
.stompClient = Stomp.client('ws://localhost:8080/test');
Finally,
If someone wants to use SockJS
client to connect, they can connect using
var socket = new SockJS('http://localhost:8080/test');
stompClient = Stomp.over(socket);
If someone wants to use just a plain Websocket
object to connect, use the following.
stompClient = Stomp.client('ws://localhost:8080/test');
I posted this solution as this will be useful to someone out there who had a similar painful experience, and they might find it useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With