Search code examples
spring-websocket

Header problems with use of convertAndSendToUser method in Spring WebSocket


I'm trying to send a message directly to an user using SimpMessageSendingOperations or SimpMessagingTemplate but both doesn't work.

simpMessagingTemplate.convertAndSend("/user/" + userSessionId + "/queue/greetings", "Message One");

messagingTemplate.convertAndSendToUser(userSessionId, "/queue/greetings", "Message Two");

I already inspected the internal classes to understand the problem and seems to be the headers. For example, if I create a StompHeaderAccessor and specially add any nativeHeaders and also add SessionId header and send as the last parameter of convertAndSendToUser it works.

StompHeaderAccessor headerAccessor = StompHeaderAccessor.create(StompCommand.SEND);
headerAccessor.setSessionId(purchaseReport.getSessionId());
headerAccessor.setNativeHeader("Any header", "Any header");

messagingTemplate.convertAndSendToUser(purchaseReport.getSessionId(), "/queue/greetings", "Message Two", headerAccessor.toMap());

Because inside the SimpMessagingTemplate class there is a method called processHeadersToSend and if there is any Native headers it returns the same headers so in AbstractMessageSendingTemplate class the type of headersToUse variable changes to a HashMap and the behavior is different.

I also created a method annotated with @SendToUser to understand the idea and the same behavior happens:

@MessageMapping({ "/hello/{id}/websocket" })
@SendToUser(value = "/queue/greetings")
String generate(@DestinationVariable Integer id, @Payload Report report,
                  SimpMessageHeaderAccessor headerAccessor) throws Exception {

messagingTemplate.convertAndSendToUser(headerAccessor.getHeader("simpSessionId").toString(),
                "/queue/greetings", "This message doesn't work");


messagingTemplate.convertAndSendToUser(headerAccessor.getHeader("simpSessionId").toString(),
                "/queue/greetings", "This one works because have native headers", headerAccessor.toMap());


return "This one send by annotation works too";

I'd like what I'm doing wrong or I really need to always instantiate a HeaderAccessor and add any native headers to work?

Thanks in advance.


Solution

  • I understand and solve my problem, I didn't pay attention to the JavaDoc description in processHeadersToSend.

    The convertAndSendToUser accepts a Map<String, Object> parameter as the headers, but correct is send a MessageHeaders if I want to keep my own headers.

    So I created a method:

        private MessageHeaders createHeaders(String sessionId) {
            SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
                    .create(SimpMessageType.MESSAGE);
            headerAccessor.setSessionId(sessionId);
            headerAccessor.setLeaveMutable(true);
            return headerAccessor.getMessageHeaders();
    
        }
    

    And call convertAndSendToUser like this:

    messagingTemplate.convertAndSendToUser(purchaseReport.getSessionId(),
                        "/queue/greetings",
                        payload,
                        createHeaders(sessionId));
    

    Thanks.