Spring 启动 WebSocket - 将正文添加到 CONNECT 响应

Spring Boot WebSocket - Adding body to the CONNECT response

我有以下 JS 函数,它们通过 STOMP 连接到 WebSocket,并分别处理 onConnected 事件。

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');
}

现在函数的第一行 onConnected,它将以下内容记录到控制台中,显然我可以从服务器端向其中添加更多数据。

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

我还有一个 HttpHandshakeInterceptor 实现 HandshakeInterceptor 如下。

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

***开头的注释行是我现在正在做的,但没有成功。我究竟做错了什么?我什至可以这样做并向客户提供一些参数吗?如果我做错了,如何以及在哪里做对? (因为现在我开始觉得我在错误的地方尝试这样做)

好的。所以以下是我尝试做的,没有成功

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;
    }
}

这基本上是拦截服务器中的出站消息,如果消息是 CONNECTED,它会添加一些自定义 header(是的,我试图添加 body 最初,但出于测试目的,我暂时坚持使用 header。

但是这种方法可以拦截很多STOMP命令,除了CONNECTED。我没有试图拦截其他人,但应该有。

然后我再次参考了STOMP Protocol Spec(感谢@TimBish 上面的评论)并从那里阅读了这个声明。

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

因此,似乎我们无法拦截除 SENDMESSAGEERROR 之外的消息。我认为这是因为遵守 Spring 的 STOMP 实现的协议规范。

为什么我尝试这样做是为了在每个连接的客户端和服务器之间共享一些共同的秘密,其中秘密由服务器决定。还在寻找这样的实现。