Open mlhummon opened 7 years ago
For me it looks like ProxyWebSocketConnectionManager making subscription per raw destination is the issue.
For example: If the user subscribes to /user/topic/messages it should be mapped to something like "/user/xxx/topic-[SESSION_ID], which will make the user receive only messages targeting his session.
/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java might be the hint
@mthizo247 What do you think?
I got the same problem, I tried to send a topic message, the message would be received twice when there was two tabs.
Do you have solved it?@tkec
No @minlingchao1
I have solved it
@minlingchao1 Could you share your solution, please?
@endario it's hard to solve that , and my solution is let it go , but we need change the project code behind the zuul project, modifying convertAndSend to convertAndSendToUser + loop, or you can say modifying topic to queue + loop , like bellow:
@MessageMapping("/sendToTopic")
public void handleChassst(Principal principal, String msg){
System.out.println("principal = [" + principal.getName() + "], msg = [" + msg + "]");
Map<String, Message<?>> tokens = WebSocketConfig.tokens;
Set<String> tokensSet = tokens.keySet();
for (Iterator<String> iterator = tokensSet.iterator(); iterator.hasNext(); ) {
String toUser = iterator.next();
simpMessagingTemplate.convertAndSendToUser(toUser, "/queue/notifications",
toUser + "__" + content);
}
}
while tokens contains all the sessions user alive, and then change the method : com.github.mthizo247.cloud.netflix.zuul.web.socket.ProxyWebSocketConnectionManager#handleFrame
to:
@Override
public void handleFrame(StompHeaders headers, Object payload) {
if (headers.getDestination() != null) {
String destination = headers.getDestination();
if (logger.isDebugEnabled()) {
logger.debug("Received " + payload + ", To " + headers.getDestination());
}
Principal principal = userAgentSession.getPrincipal();
String userDestinationPrefix = messagingTemplate.getUserDestinationPrefix();
if (destination.startsWith(userDestinationPrefix)) {
String substring = destination.substring(userDestinationPrefix.length());
int i = substring.indexOf("/");
String dest = substring.substring(0, i);
String[] queues = zuulWebSocketProperties.getQueues();
String[] topics = zuulWebSocketProperties.getTopics();
destination = destination.substring(userDestinationPrefix.length());
destination = destination.startsWith("/") ? destination:"/" + destination;
if (Arrays.asList(queues).contains(dest)) {
String payStr = payload.toString();
int index = payStr.indexOf("__");
String toUserId = payStr.substring(0, index);
String msg = payStr.substring(index + "__".length());
messagingTemplate.convertAndSendToUser(toUserId, destination,
msg, copyHeaders(headers.toSingleValueMap()));
} else if (Arrays.asList(topics).contains(dest)) {
Set<String> strings = ProxyWebSocketHandler.tokens.keySet();// TODO
for (Iterator<String> iterator = strings.iterator(); iterator.hasNext(); ) {
String next = iterator.next();
messagingTemplate.convertAndSendToUser(next, destination,
payload, copyHeaders(headers.toSingleValueMap()));
}
} else {
logger.error("Cannot send msg :" + destination);
}
} else {
messagingTemplate.convertAndSend(destination, payload,
copyHeaders(headers.toSingleValueMap()));
}
}
}
as in my project , we authenticate users by token, so principal is not available, so , i conbined toUserId with the payload, and then convertAndSendToUser ...
I'm using this to send messages to users that may have multiple tabs/windows open. I noticed in this case duplicate messages are sent from the proxy. I can also reproduce this with the demo, https://github.com/mthizo247/zuul-websocket-support-demo.
When using the demo, start the proxy and hello app. Open two tabs or windows going through the proxy, http://localhost:7078/, and click connect on both. Enter your name in the "What's your name?" input box, then click send. Observe in the console that two "MESSAGE" responses are received in both. If you have three tabs or windows open, then three "MESSAGE" responses are sent to each.
If you do the same thing going directly to the hello app, http://localhost:7079/, you don't get the duplicate messages.