【问题标题】:Returning header to STOMP client frame object after handshake握手后将标头返回到 STOMP 客户端框架对象
【发布时间】:2015-04-02 17:24:34
【问题描述】:

目前,当成功连接到端点时,我通过响应标头将自定义令牌(称为访问令牌)传递回客户端。此标头设置正确,我可以通过分析 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);

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

【问题讨论】:

    标签: java javascript spring websocket stomp


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      您需要实现 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);
          }
      }
      

      【讨论】:

        【解决方案3】:

        恐怕如果没有重大黑客攻击,这是不可能的。问题是,在调用 ChannelInterceptors 之后,标头会完全重建。见方法StompSubProtocolHandler.convertConnectAcktoStompConnected

        StompSubProtocolHandler.handleMessageToClient 方法还将根据消息的类型添加一些标头,例如通过调用 afterStompSessionConnected 来设置标头“用户名”(如果身份验证完成)。

        我也尝试过添加标头,但我即将放弃...我的猜测是在 Spring 中编写 STOMP 实现的人希望严格尊重 the specifications

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-05
          • 1970-01-01
          相关资源
          最近更新 更多