Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicate response messages sent when multiple browser tabs/windows are open #4

Open
mlhummon opened this issue Jun 16, 2017 · 8 comments

Comments

@mlhummon
Copy link

mlhummon commented Jun 16, 2017

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.

@mpodlodowski
Copy link
Contributor

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?

@tkec
Copy link

tkec commented Feb 4, 2018

I got the same problem, I tried to send a topic message, the message would be received twice when there was two tabs.

@minlingchao1
Copy link

minlingchao1 commented Feb 8, 2018

Do you have solved it?@tkec

@tkec
Copy link

tkec commented Mar 19, 2018

No @minlingchao1

@minlingchao1
Copy link

minlingchao1 commented Mar 19, 2018

I have solved it

@endario
Copy link

endario commented Jun 12, 2018

@minlingchao1 Could you share your solution, please?

@R1310328554
Copy link

R1310328554 commented Jul 13, 2018

@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()));
        }
    }
}

@R1310328554
Copy link

as in my project , we authenticate users by token, so principal is not available, so , i conbined toUserId with the payload, and then convertAndSendToUser ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants