I am currently developing a Web Socket for internal and external requests. However, while trying to test the bidirectional connection via a Chrome command I received the following error:
"Origin 'null' is therefore not allowed access."
Web Socket configuration:
#Configuration
#EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer{
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/bidirectional");
}
public void registerStompEndpoints(StompEndpointRegistry registry) {
//register a new endpoint
registry.addEndpoint("/blueframe").setAllowedOrigins("/*");
registry.addEndpoint("/blueframe").setAllowedOrigins("/*").withSockJS();
}
}
JavaScript connection:
var socket = new SockJS('http://192.168.137.23:8080/blueframe');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
});
I already tried to see other posts with no results.
First i quitted using Webservices, instead i start using RabbitMQ for a bidirectional communication.
Regarding Web Socket Configuration, i am not the only one having this problem so i found a parcial solution: Downgrade the Spring version or use Socket handlers instead of StompEndpointRegistry interface.
Related
I want to initiate a trigger(maybe a notification) from backend(based in spring boot) to a particular user whose userId is xyz.
the one way i have found is:
initially i connect to a websocket end point and subscribe to channel "/user/Notifications/xyz"
following is the relevant code in my angular typescript
connectToUserWebSocket(userId) {
let socket = new SockJS('http://localhost:5000/fellowGenius');
this.ws = Stomp.over(socket);
let that = this;
this.ws.connect(
{},
(frame) => {
that.ws.subscribe('/user/Notifications/' +userId, (message) => {
console.log("user subscribed");
});
},
(error) => {
alert('STOMP error ' + error);
}
);
}
Now once i have subscribed to my channel . I want to send a trigger to client which is initiated by backend itself so i run a code in my java service.
My relevant java code is:
#SendTo("/user/Notifications/{userId}")
public String sendMeetingNotificationWebSocket(#DestinationVariable String userId) {
return "hello";
}
my websocket configurations are:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/fellowGenius").setAllowedOrigins("*").addInterceptors(new HttpSessionHandshakeInterceptor()).withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/inbox/","/user/Notifications/");
}
}
But the problem is that even i can see one web socket connected in my spring boot console.
But i don't get a response from the function on the client side.
Please help me with this problem.
I want to send notification to specific client.
e.g username user
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends
AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
registry.setApplicationDestinationPrefixes("/app");
}
Controller
#GetMapping("/notify")
public String getNotification(Principal principal) {
String username = "user";
notifications.increment();
logger.info("counter" + notifications.getCount() + "" + principal.getName());
// logger.info("usersend:"+sha.getUser().getName()) ; //user
template.convertAndSendToUser(principal.getName(), "queue/notification", notifications);
return "Notifications successfully sent to Angular !";
}
Client-Side
Angular Service
connect() {
let socket = new SockJs(`api/socket`);
let stompClient = Stomp.over(socket);
return stompClient;
}
Angular Component
let stompClient = this.webSocketService.connect();
stompClient.connect({}, frame => {
stompClient.subscribe('/user/queue/notification', notifications => {
console.log('test'+notifications)
this.notifications = JSON.parse(notifications.body).count;
}) });
I am have searched many other questions and tried but none of them worked for me
e.g here answered by Thanh Nguyen Van and here
Console
Opening Web Socket...
stomp.js:134 Web Socket Opened...
stomp.js:134 >>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
stomp.js:134 <<< CONNECTED
version:1.1
heart-beat:0,0
stomp.js:134 connected to server undefined
reminder.component.ts:18 test callsed
stomp.js:134 >>> SUBSCRIBE
id:sub-0
destination:/user/queue/notification
thanks in advance .
The answer of gerrytan to Sending message to specific user on Spring Websocket mentions a web socket configuration change, to register the /user prefix. In your case I guess it means to replace
registry.enableSimpleBroker("/topic", "/queue");
with
registry.enableSimpleBroker("/topic", "/queue", "/user");
He also says that in controller you don't need the /user prefix because it is added automatically. So you could try this:
template.convertAndSendToUser(principal.getName(), "/queue/notification", notifications);
and this:
template.convertAndSendToUser(principal.getName(), "/user/queue/notification", notifications);
On the client side you need to provide the username that you used to connect to server. You might insert it directly:
stompClient.subscribe('/user/naila/queue/notification', ...)
or get it from a header. But Markus says at How to send websocket message to concrete user? that even here you don't need the username, so it might work like this:
stompClient.subscribe('/user/queue/notification', ...)
Seems you are missing a slash in your destination:
template.convertAndSendToUser(principal.getName(), "/queue/notification", notifications);
I have this websocket server developed using Spring Boot. The server is working fine with a js based client.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS();
registry.addEndpoint("/chat");
}
}
The controller:
#Controller
public class ChatController {
#MessageMapping("/chat")
#SendTo("/topic/messages")
public OutputMessage send(final Message message) throws Exception {
final String time = new SimpleDateFormat("HH:mm").format(new Date());
return new OutputMessage(message.getFrom(), message.getText(), time);
}
}
This is the server side. Now, for the client, I have created a #ClientEndpoint and when I connect to the URI "ws://localhost:8080/spring-mvc-java/chat", I am able to establish a connection and I can see that the #OnOpen callback of #ClientEndpoint is triggered.
However, it seems that the userSession.getAsyncRemote().sendText(message) does not have any effect. I don't see the response from the server.
I can see the js client is:
Connecting to the server var socket = new SockJS('/spring-mvc-java/chat')
Subscribing stompClient.subscribe('/topic/messages',...
Send the message stompClient.send("/app/chat",...
I am able to achieve the first step. How to achieve the 2nd and the 3rd step in a Java based client?
Thanks
First of all you need a websocketclient and websocketstompclient
WebSocketClient client = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(client);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
You have to custom handler from StompSessionHandler for
getPayloadType
handleFrame
afterConnected
handleException
handleTransportError
methods
StompSessionHandler sessionHandler = new CustomStompSessionHandler();
You can connect your sockets like this. You can accomplish sending and receiving messages
StompSession stompSession=stompClient.connect("ws://localhost:8080/chat",sessionHandler).get();
This two trigger your websocket topic/messages give you messages through the sockets
/app/chat sending Message to sockets
stompSession.subscribe("/topic/messages", sessionHandler);
stompSession.send("/app/chat", new Message("Hi", "user"));
do you want like this?
Is there a way to use WebSockets with SockJS client and Spring 4 server but not using STOMP?
Based on this tutorial from Spring's website, I know how to set up a WebSocket based application using Stomp and Spring 4. On the client side, we have:
var socket = new SockJS('/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function(greeting){
showGreeting(JSON.parse(greeting.body).content);
});
});
And on the server side, we have the following in the controller:
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(3000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
Now, I understand that #MessageMapping("/hello") ensures that if a message is sent to a destination "/hello", then the greeting() method will be called. And since the stompClient is subscribed to "/topic/greetings", the #SendTo("/topic/greetings") will send the message back to the stompClient.
But the problem with the above is that stompClient is a Stomp object. And I want to simply use sock.send('test'); and have it delivered to my server's destination. And I want to do #SendTo("myownclientdestinationmap"), I can receive it by
sock.onmessage = function(e) {
console.log('message', e.data);
};
So, any way to do this with Spring 4, SockJS and without Stomp? Or does Spring 4 WebSocket only supports Stomp?
Spring supports STOMP over WebSocket but the use of a subprotocol is not mandatory, you can deal with the raw websocket. When using a raw websocket, the message sent lacks of information to make Spring route it to a specific message handler method (we don't have any messaging protocol), so instead of annotating your controller, you'll have to implement a WebSocketHandler:
public class GreetingHandler extends TextWebSocketHandler {
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
Thread.sleep(3000); // simulated delay
TextMessage msg = new TextMessage("Hello, " + message.getPayload() + "!");
session.sendMessage(msg);
}
}
And then add your handler to the registry in the configuration (you can add more than one handler and use SockJS for fallback options):
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(greetingHandler(), "/greeting").withSockJS();
}
#Bean
public WebSocketHandler greetingHandler() {
return new GreetingHandler();
}
}
The client side will be something like this:
var sock = new SockJS('http://localhost:8080/greeting');
sock.onmessage = function(e) {
console.log('message', e.data);
}
I need to manage a single WebSocket connection in a Android application. For this I implemented a web application where set up a WebSocket Message Broker using Spring, as its quick start.
The problem is that I could not make a connection in my Android application. I'm using Autobahn Android, but I can not connect to subscribe and publish on topics (like SockJS with STOMP).
Server (Spring):
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/ws"></websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic"/>
</websocket:message-broker>
#Controller
public class MessageController {
#MessageMapping("/ws")
#SendTo("/topic/poc")
public MyEntity proofOfConcept(String message) throws Exception {
return new MyEntity(message);
}
}
Client (Autobahn Android):
final String wsuri = "ws://" + HOSTNAME + ":" + PORT + "/myapp/ws";
mConnection.connect(wsuri, new Wamp.ConnectionHandler() {
#Override
public void onOpen() {
mConnection.subscribe("/myapp/ws/topic/poc", MyEntity.class, new Wamp.EventHandler() {
#Override
public void onEvent(String topicUri, Object event) { }
});
}
#Override
public void onClose(int code, String reason) {
// ERROR: Could not connect to /HOSTNAME...
}
});
I managed to connect using simple handlers of spring instead of message broker, but that limits me to "listen" only one endpoint per connection... Could anyone help me please?
AutobahnAndroid implements WebSocket and WAMP, not STOMP. Different from STOMP, WAMP provides both Publish & Subcribe and Remote Procedure Calls.
For using WAMP, you will need a WAMP Router. You can find client and router implementations for WAMP here.