How to send websocket message from server to specific user only?
My webapp has spring security setup and uses websocket. I'm encountering tricky problem trying to send message from server to specific user only.
My understanding from reading the manual is from the server we can do
simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply);
And on the client side:
stompClient.subscribe('/user/reply', handler);
But I could never get the subscription callback invoked. I have tried many different path but no luck.
If I send it to /topic/reply it works but all other connected users will receive it too.
To illustrate the problem I've created this small project on github: https://github.com/gerrytan/wsproblem
Steps to reproduce:
1) Clone and build the project (make sure you're using jdk 1.7 and maven 3.1)
$ git clone https://github.com/gerrytan/wsproblem.git
$ cd wsproblem
$ mvn jetty:run
2) Navigate to http://localhost:8080
, login using either bob/test or jim/test
3) Click "Request user specific msg". Expected: a message "hello {username}" is displayed next to "Received Message To Me Only" for this user only, Actual: nothing is received
I created a sample websocket project using STOMP as well. What I am noticing is that
}
it works whether or not "/user" is included in config.enableSimpleBroker(...
Oh,
client side no need to known about current user
, server will do that for you.On server side, using following way to send message to an user:
Note: Using
queue
, nottopic
, Spring always usingqueue
withsendToUser
On client side
Explain
When any websocket connection is open, Spring will assign it a
session id
(notHttpSession
, assign per connection). And when your client subscribe to an channel start with/user/
, eg:/user/queue/reply
, your server instance will subscribe to a queue namedqueue/reply-user[session id]
When use send message to user, eg: username is
admin
You will writesimpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);
Spring will determine which
session id
mapped to useradmin
. Eg: It found two sessionwsxedc123
andthnujm456
, Spring will translate it to 2 destinationqueue/reply-userwsxedc123
andqueue/reply-userthnujm456
, and it send your message with 2 destinations to your message broker.The message broker receive the messages and provide it back to your server instance that holding session corresponding to each session (WebSocket sessions can be hold by one or more server). Spring will translate the message to
destination
(eg:user/queue/reply
) andsession id
(eg:wsxedc123
). Then, it send the message to correspondingWebsocket session
Exactly i did the same and it is working without using user
My solution of that based on Thanh Nguyen Van's best explanation, but in addition I have configured MessageBrokerRegistry:
Ah I found what my problem was. First I didn't register the
/user
prefix on the simple brokerThen I don't need the extra
/user
prefix when sending:Spring will automatically prepend
"/user/" + principal.getName()
to the destination, hence it resolves into "/user/bob/reply".This also means in javascript I had to subscribe to different address per user