I'm working on a Spring Boot application using STOMP over WebSocket. In my UI client app, I receive the CONNECTED frame like this:
["CONNECTED\nversion:1.2\nheart-beat:0,0\n\n\u0000"]
However, I need the sessionId to be included in the CONNECTED frame.
Is there a way to include the sessionId in the CONNECTED frame sent to the client? If not directly possible, is there a recommended workaround to pass the session ID to the client in CONNECTED frame? I tried to intercept CONNECTED frame using clientOutbound Channel interceptor, but it is not intercepting CONNECTED frame at all, but if I register a inboundChannel I can intercept all the frames sent from client(CONNECT, SEND, SUBSCRIBE).
WebSocket Config class
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* Websocket Configuration class
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private final CustomHandshakeInterceptor customHandshakeInterceptor;
/**
* Constructs a {@code WebSocketConfig} with the specified interceptors.
*
*/
public WebSocketConfig(CustomHandshakeInterceptor customHandshakeInterceptor) {
this.customHandshakeInterceptor = customHandshakeInterceptor;
}
/**
* Registers the WebSocket endpoint and configures SockJS support.
*
* @param registry the StompEndpointRegistry to register endpoints
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").addInterceptors(customHandshakeInterceptor).setAllowedOriginPatterns("*").withSockJS();
}
/**
* Configures the message broker for WebSocket communication.
*
* @param config the MessageBrokerRegistry to configure message broker
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/cdsoutput");
config.enableSimpleBroker("/topic");
}
/**
* Configures the client inbound channel to intercept messages from client to server.
* This intercepts: CONNECT, SEND, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT
*
* @param registration the ChannelRegistration to configure the inbound channel
*/
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ManualChannelInterceptor());
}
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.interceptors(new ManualChannelInterceptor());
}
}
ManualChannelInterceptor class:
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class ManualChannelInterceptor implements ChannelInterceptor {
/**
* Called BEFORE sending a message through the channel.
* This is where you can intercept, log, or modify messages.
*/
@Override
public Message> preSend(Message> message, MessageChannel channel) {
final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (accessor == null) {
return message;
}
StompCommand command = accessor.getCommand();
String sessionId = accessor.getSessionId();
String username = accessor.getUser() != null ? accessor.getUser().getName() : "anonymous";
// Log every message type
log.info(">>> preSend: Command={}, SessionId={}, User={}, Destination={}",
command, sessionId, username, accessor.getDestination());
if (SimpMessageType.CONNECT_ACK.equals(accessor.getMessageType())) {
log.info(">>>>>>>>> CONNECT_ACK frame (server → client) - Added session-id header: {}", sessionId);
accessor.setSessionId(sessionId);
}
if (StompCommand.CONNECT.equals(command)) {
log.info(">>>>>>>>> CONNECT frame (client → server) - SessionId: {}", sessionId);
}
if (StompCommand.CONNECTED.equals(command)) {
log.info(">>>>>>>>> CONNECTED frame (server → client) - Added session-id header: {}", sessionId);
}
if (StompCommand.MESSAGE.equals(command)) {
log.info(">>>>>>>>> MESSAGE frame (broker → client) - Destination: {}", accessor.getDestination());
}
if (StompCommand.SEND.equals(command)) {
log.info(">>>>>>>>> SEND frame (client → server) - From user: {}", username);
}
if (StompCommand.SUBSCRIBE.equals(command)) {
log.info(">>>>>>>>> SUBSCRIBE frame (client → server) - User: {}, Destination: {}", username, accessor.getDestination());
}
if (StompCommand.UNSUBSCRIBE.equals(command)) {
log.info(">>>>>>>>> UNSUBSCRIBE frame (client → server) - User: {}", username);
}
if (StompCommand.ACK.equals(command)) {
log.info(">>>>>>>>> ACK frame - User: {}", username);
}
if (StompCommand.DISCONNECT.equals(command)) {
log.info(">>>>>>>>> DISCONNECT frame (client → server) - User: {}", username);
}
return message;
}
}
Logs are printing for SEND, CONNECT, SUBSCRIBE, basically all frames sent from client, but it is not detecting CONNECTED frame which is sent from server to client.
Please help me to get sessionId in the CONNECTED frame.