Romeo Sierra
Romeo Sierra

Reputation: 1756

Spring Boot WebSocket - Adding body to the CONNECT response

I have the following JS functions, which are connecting to a WebSocket over STOMP, and handling the onConnected events, respectively.

function connect(event) {
    username = document.querySelector('#name').value.trim();

    if(username) {
        usernamePage.classList.add('hidden');
        chatPage.classList.remove('hidden');

        var socket = new SockJS('/ws');
        stompClient = Stomp.over(socket);

        stompClient.connect({}, onConnected, onError);
    }
    event.preventDefault();
}


function onConnected(response) {
    console.log(response);
    // Subscribe to the Public Topic
    stompClient.subscribe('/topic/public', onMessageReceived);

    // Tell your username to the server
    stompClient.send("/app/chat.addUser",
        {},
        JSON.stringify({sender: username, type: 'JOIN'})
    )

    connectingElement.classList.add('hidden');
}

Now the first line of the function onConnected, it logs the following into the console, which apparently looks like something I could add more data into, from the server side.

{
    command: "CONNECTED",
    headers: { 
        "heart-beat": "0,0",
        version: "1.1"
    },
    body: ""
}

I also have an HttpHandshakeInterceptor which implements HandshakeInterceptor as follows.

@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
        Map attributes) throws Exception {
    if (request instanceof ServletServerHttpRequest) {
        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
        HttpSession session = servletRequest.getServletRequest().getSession();
        attributes.put("sessionId", session.getId());

        ServletServerHttpResponse servletResponse = (ServletServerHttpResponse) response;
        response.getHeaders().set("KEY","VALUE"); // *** I want this either to be in the response header or the body.
    }
    return true;
}

The line that has a comment starting with *** is what I am doing right now with no success. What am I doing wrong? Can I even do this and get some parameters there to the client? If I am doing it wrong, how and where to do it right? (because now I am starting to feel like I am trying to do this in the wrong place)

Upvotes: 1

Views: 1807

Answers (1)

Romeo Sierra
Romeo Sierra

Reputation: 1756

Okay. So the following is what I have tried to do, with no success.

public class OutboundMessageInterceptor implements ChannelInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(OutboundMessageInterceptor.class);

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        final StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
        final StompCommand command = headerAccessor.getCommand();

        LOGGER.info("Outbound channel preSend (" + command + ")...");

        if (command != null) {

            switch (command) {

                case CONNECTED:
                    final StompHeaderAccessor accessor = StompHeaderAccessor.create(headerAccessor.getCommand());
                    accessor.setSessionId(headerAccessor.getSessionId());
                    @SuppressWarnings("unchecked")
                    final MultiValueMap<String, String> nativeHeaders = (MultiValueMap<String, String>) headerAccessor.getHeader(StompHeaderAccessor.NATIVE_HEADERS);
                    accessor.addNativeHeaders(nativeHeaders);

                    // add custom headers
                    accessor.addNativeHeader("CUSTOM01", "CUSTOM01");

                    return MessageBuilder.createMessage(new byte[0], accessor.getMessageHeaders());
                default:
                    break;
            }
        }

        return message;
    }
}

What this basically does is, intercepting the outbound messages in the server and, if the message is CONNECTED, it will add some custom header (yes I was trying to add body originally, but for testing purposes I stuck to the header for the time being).

However this method can intercept many STOMP commands, except CONNECTED. I didn't try to intercept others but there probably should be.

Then I again referred to the STOMP Protocol Spec (thanks to @TimBish for his comment above) and read this statement from there.

Only the SEND, MESSAGE, and ERROR frames MAY have a body. All other frames MUST NOT have a body.

So, it seems like we cannot intercept the messages except for SEND, MESSAGE & ERROR. I presume it is because of the adherence to the protocol spec of Spring's STOMP implementation.

Why I tried doing this was to share some common secret between each client connected and the server, where the secret is determined by the server. Still looking for such implementation.

Upvotes: 3

Related Questions