【问题标题】:How to add custom headers to STOMP CREATED message in Spring Boot application?如何在 Spring Boot 应用程序中向 STOMP CREATED 消息添加自定义标头?
【发布时间】:2017-06-29 05:16:55
【问题描述】:

我正在尝试将自定义标头添加到客户端在第一次连接时收到的 STOMP 'CREATED' 消息。这是使用 STOMP JavaScript 连接到 WebSocket 的函数:

function connect() {
    socket = new SockJS('/chat');
    stompClient = Stomp.over(socket);
    stompClient.connect('', '', function(frame) {
      whoami = frame.headers['user-name'];
      console.log(frame);
      stompClient.subscribe('/user/queue/messages', function(message) {
          console.log("MESSAGE RECEIVED:");
          console.log(message);

        showMessage(JSON.parse(message.body));
      });
      stompClient.subscribe('/topic/active', function(activeMembers) {
        showActive(activeMembers);
      });
    });
  }

此函数将以下内容打印到浏览器的控制台:

body: ""
command: "CONNECTED"
headers: Object
    heart-beat: "0,0"
    user-name: "someuser"
    version: "1.1"

我想添加自定义标题,所以输出必须如下所示:

body: ""
command: "CONNECTED"
headers: Object
    heart-beat: "0,0"
    user-name: "someuser"
    version: "1.1"
    custom-header: "foo"

我的 Spring Boot 应用中有以下 WebSocket 配置。

WebSocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker("/queue", "/topic");
    config.setApplicationDestinationPrefixes("/app");
  }

  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/chat", "/activeUsers")
            .withSockJS()
            .setInterceptors(customHttpSessionHandshakeInterceptor());
  }

  ...

  @Bean
  public CustomHttpSessionHandshakeInterceptor 
        customHttpSessionHandshakeInterceptor() {
        return new CustomHttpSessionHandshakeInterceptor();

  }

}

我尝试注册“HandshakeInterceptor”来设置自定义标头,但没有成功。这是“CustomHttpSessionHandshakeInterceptor”:

CustomHttpSessionHandshakeInterceptor.java

public class CustomHttpSessionHandshakeInterceptor implements 

HandshakeInterceptor {

     @Override
        public boolean beforeHandshake(ServerHttpRequest request,
        ServerHttpResponse response,
        WebSocketHandler wsHandler,
        Map<String, Object> attributes) throws Exception {
            if (request instanceof ServletServerHttpRequest) {


                 ServletServerHttpRequest servletRequest =
                    (ServletServerHttpRequest) request;
                 attributes.put("custom-header", "foo");
            }
            return true;
        }

        public void afterHandshake(ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Exception ex) { }
}

我在https://dzone.com/articles/spring-boot-based-websocket 找到了这个代码 sn-p
有人可以解释一下为什么这种方法不起作用吗?是否有另一种方法可以在 Spring Boot 应用程序的服务器端为 STOMP 'CREATED' 消息设置自定义标头?
谢谢!

【问题讨论】:

    标签: spring spring-boot websocket stomp spring-websocket


    【解决方案1】:

    【讨论】:

    • 是的,我尝试使用 'MessageHeaderAccessor',它非常适用于带有 STOMP 'MESSAGE' 命令的消息(对于由使用 Spring 的'@MessageMapping' 注释并由'SimpMessagingTemplate'发送的方法处理的普通消息) '在我的情况下)。问题是如何使用 STOMP 'CONNECTED' 命令为消息添加自定义标头,该命令在建立 WebSocket 连接后由服务器发送?
    【解决方案2】:

    也许为时已晚,但迟到总比没有好......

    服务器消息(例如 CONNECTED)是不可变的,意味着它们不能被修改。

    我要做的是注册一个客户端出站拦截器并通过覆盖 preSend(...) 方法捕获连接的消息并使用我的自定义标头构建一个新消息。

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) 
    {
        LOGGER.info("Outbound channel pre send ...");
        final StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
        final StompCommand command = headerAccessor.getCommand();
        if (!isNull(command)) {
            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");
    
                    final Message<?> newMessage = MessageBuilder.createMessage(new byte[0], accessor.getMessageHeaders());
                    return newMessage;
                default:
                    break;
                }
            }
            return message;
        }
    

    @UPDATE:::

    所需的接口称为ChannelInterceptor,要注册您自己的实现,您需要添加@Configuration带注释的类

    @Configuration
    public class CustomMessageBrokerConfig extends WebSocketMessageBrokerConfigurationSupport
    implements WebSocketMessageBrokerConfigurer{}
    

    并覆盖一个方法 configureClientOutboundChannel 如下

    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        log.info("Configure client outbound channel started ...");
        registration.interceptors(new CustomOutboundChannelInterceptor());
        log.info("Configure client outbound channel completed ...");
    }
    

    【讨论】:

    • 对我来说,这个答案缺少很多支持方面。比如类应该长什么样,扩展了哪些类,实现了哪些接口,最后在哪里以及如何注册这个拦截器。如果这些在那里,我认为这将是一个很好的答案..
    • @RomeoSierra 我完全同意,这就像一个提示,而不是一个完整的答案。请在上面查看我的更新。
    • @TheReALDeAL 我在final StompCommand command = headerAccessor.getCommand();得到了空值
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-15
    • 2018-08-02
    • 1970-01-01
    • 2014-02-24
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    相关资源
    最近更新 更多