2

I have problem when I try to send message from client to server on Spring websocket. I have configuration Websocket on server and create @Message on controller. I send data from client via javascript. It just work sometimes, but sometimes it fail and throw message on server: MissingSessionUserException: No "user" header in message

Here're my WebsocketConfig:

public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/connectsocket").withSockJS();
    }
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/");
    }
}

Here're my MessageController:

@RestController
public class MessageController {

    @Autowired
    private SimpMessagingTemplate template;

    @MessageMapping("/websocket/message")
    public synchronized void message(Message<Object> messageObj, 
        WebMessage message, Principal principal) throws Exception {
        if (principal != null) {
            String name = principal.getName();
            template.convertAndSendToUser(name, "/topic/dynamic", new MessagePojo("stage", "value", "message"));
        }
    }
}

Here're my Javascript-backbonejs code:

app.Models.WebsocketModel = Backbone.Model.extend({
    fetchData : function() {
        console.log("WebsocketModel: fetchData");
        var socket = new SockJS(url + "/connectsocket");
        var client = Stomp.over(socket);

        var onConnect = function(frame) {
            console.log('Connected: ' + frame);
            client.subscribe("/user/topic/dynamic", function(data) {
                var jsonBody = JSON.parse(data.body);
                console.log(jsonBody);
            });
        };

        client.connect({}, onConnect);

        setInterval(function() {
            client.send("/websocket/message", {}, JSON.stringify({
                "message" : "Hello world!!!",
                "toUser" : "Someone"
            }));
        }, 10000);
    }
});

Here're my server error log:

[2016 Apr 14 - 02:13:19] ERROR: [org.springframework.web.socket.messaging.WebSocketAnnotationMethodMessageHandler] - Unhandled exception org.springframework.messaging.simp.annotation.support.MissingSessionUserException: No "user" header in message at org.springframework.messaging.simp.annotation.support.PrincipalMethodArgumentResolver.resolveArgument(PrincipalMethodArgumentResolver.java:42) at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:139) at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:108) at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:497) at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:87) at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)

m.nguyencntt
  • 935
  • 13
  • 19

1 Answers1

6

You are trying to subscribe to a user destination so the user must be authenticated.

If that is an anonymous user who want to subscribe to the topic, answer to this question will help.

You'll have to assign an anonymous identify to the user and there are two options:

  1. Configure a sub-class of DefaultHandshakeHandler that overrides determineUser and assigns some kind of identity to every WebSocketSession.

  2. The WebSocket session will fall back on the value returned from HttpServletRequest.getUserPrincipal on the handshake HTTP request. You could have a servlet Filter wrap the HttpServletRequest and decide what to return from that method. Or if you're using Spring Security which has the AnonymousAuthenticationFilter, override its createAuthentication method.

Community
  • 1
  • 1
Stanley
  • 5,057
  • 4
  • 34
  • 44
  • 1
    Thanks for your comment @Stanley. I have solved my issues a long times ago and it's the same with you suggestion. It will be helpful for other one like me. In the past, I checked header on network before client send to server, then I see missing user authentication. After that I just add user authentication before client send to server and it works fine. – m.nguyencntt Nov 28 '16 at 04:34