握手后将头返回到STOMP客户端帧对象

时间:2015-04-02 17:24:35

标签: java javascript spring websocket stomp

目前,当成功连接到端点时,我通过响应头将自定义令牌(称为访问令牌)传递回客户端。正确设置了此标头,我可以通过分析HTTP响应来验证标头。

但是,当尝试从帧对象获取标头时,标头未设置(请参阅下面的JavaScript):

 stompClient.connect(headers, 
                function(frame) {
                    console.log('=========================================');
                    console.log(frame.headers['access-token']);
                    console.log(frame);
                    console.log('=========================================');
                    stompClient.subscribe('/topic/test', function(stuff){
                       console.debug(stuff);
                    });
                },
                function(error) {
                    //error code
                }
        );

我在服务器上设置响应标头如下:

public class HttpSessionHandshakeInterceptorImpl extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
        ServerHttpResponse response, WebSocketHandler wsHandler,
        Map<String, Object> attributes) throws Exception {

        response.getHeaders().set("access-token", token);

         return super.beforeHandshake(request, response, wsHandler, attributes);

我删除了一些代码,可以确认是否正在调用拦截器。我认为这不是在调用connect函数时将标头值传递回客户端的正确方法吗?我似乎无法找到有关如何完成此任务的任何文档。感谢。

3 个答案:

答案 0 :(得分:0)

ServerHttpResponse响应 - 这是对HTTP请求的响应,您可以更详细地检查(通过记录或在调试模式下)。设置其标头将影响HTTP响应,而不是流经WebSocket连接的STOMP流。 CONNECTED的STOMP标头由消息代理设置。

我不确定,但我怀疑Spring是否能够在STOMP帧中插入额外的标头。 (如果我错了,请纠正我)

答案 1 :(得分:0)

您需要实现ChannelInterceptor并将其注册到输出绑定的通道中

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
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.MessageBuilder;
import org.springframework.util.MultiValueMap;

@Configuration
public class WebSocketServiceCustomHeaderInterceptor implements ChannelInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketServiceCustomHeaderInterceptor.class);

    @Override
    @Nullable
    public Message<?> preSend(Message<?> message, MessageChannel channel) {

        final StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
        final StompCommand command = headerAccessor.getCommand();
        if (command != null && command == StompCommand.CONNECTED) {
            final StompHeaderAccessor accessor = StompHeaderAccessor.create(command);
            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
            try {
                accessor.addNativeHeader("HOSTNAME", InetAddress.getLocalHost().getHostName());
            } catch (UnknownHostException e) {
                logger.error("Error getting host name ", e);
            }

            final Message<?> newMessage = MessageBuilder.createMessage(new byte[0], accessor.getMessageHeaders());
            return newMessage;
        }
        return message;
    }

}

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {

    @Bean
    public WebSocketServiceCustomHeaderInterceptor webSocketServiceCustomHeaderInterceptor() {
        return new WebSocketServiceCustomHeaderInterceptor();
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.interceptors(webSocketServiceCustomHeaderInterceptor());
        registration.taskExecutor().corePoolSize(outboundPoolCoreSize).maxPoolSize(outboundPoolMaxSize);
    }
}

答案 2 :(得分:0)

恐怕如果没有重大修改,这是不可能的。问题是,在调用ChannelInterceptors之后,标头已完全重建。参见方法def shout(word): return word.upper() def introduce(): name = input("What's your name: ") name = shout(name) print(f"Hello {name}") introduce()

StompSubProtocolHandler.convertConnectAcktoStompConnected方法还将根据消息的类型添加一些标头,例如,调用StompSubProtocolHandler.handleMessageToClient,如果完成身份验证,则将其设置为标头“用户名”。

我也尝试添加标头,但我要放弃...我的猜测是,在Spring编写STOMP实现的人们都希望严格遵守the specifications