spring-websocket STOMP是否支持SUBSCRIBE id?

时间:2017-07-01 05:14:29

标签: stomp spring-websocket

STOMP规范说SUBSCRIBE 必须 id标头

https://stomp.github.io/stomp-specification-1.2.html#SUBSCRIBE_id_Header

  

SUBSCRIBE id标头

     

由于单个连接可以有多个打开的订阅   服务器,ID头必须唯一地包含在帧中   识别订阅。 id标头允许客户端和服务器   将后续MESSAGE或UNSUBSCRIBE帧与原始帧相关联   订阅。在同一个连接中,不同的订阅必须   使用不同的订阅标识符。

但是,在spring的示例https://spring.io/guides/gs/messaging-stomp-websocket/中,它在订阅目标时没有指定id。

function connect() {
    var socket = new SockJS('/gs-guide-websocket');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        stompClient.subscribe('/topic/greetings', function (greeting) {
            showGreeting(JSON.parse(greeting.body).content);
        });
    });
}

在Spring的API中,SimpMessageSendingOperations。 convertAndSendToUser 不会明确支持id标头。

我的问题是如何在向客户端发送邮件时指定ID标头?

1 个答案:

答案 0 :(得分:0)

我认为您无法使用订阅ID向特定客户端发送消息。 Stomp定义了这个ID,Spring的实现在内部使用它来为订阅目标地址的每个客户端创建消息。因此,订阅ID在Stomp通信中是透明的...您可以在客户端指定它或让Stomp JS(STOMP Over WebSocket)创建一个唯一的。

如果您订阅了以" / user /&#34为前缀的目的地;并使用org.springframework.messaging.simp.SimpMessagingTemplate#convertAndSendToUserorg.​springframework.​messaging.​simp.​annotation.SendToUser向单个客户端发送消息,Spring所做的是根据原始目标注册并创建对基于自定义会话的目标的订阅。换句话说,来自Spring的Javadoc:

  

当用户尝试订阅时,例如至   " / user / queue / position-updates"," / user"删除前缀和   基于会话ID添加的唯一后缀,例如   " /队列/位置更新 - useri9oqdfzo"确保不同的用户可以   订阅相同的逻辑目的地而不会发生冲突。

     

发送给用户时,例如   " / user / {username} / queue / position-updates"," / user / {username}"   删除前缀并添加基于活动会话ID的后缀,   例如" /队列/位置更新 - useri9oqdfzo"

请参阅http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.html

请参阅https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-user-destination

已编辑:

您无法使用订阅ID直接向其订阅的客户端发送消息,但您可以使用客户端的会话ID。根据{{​​3}},您可以使用用户的名称向他发送消息。但是你需要一个带有Principal的认证会话。或者您可以在邮件的标题中强制使用目标的会话ID,从而避免内部步骤发现它,如here所示。

private void sendMessageToUser(String destinationSessionId, String message) {
    SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
    headerAccessor.setSessionId(destinationSessionId);
    headerAccessor.setLeaveMutable(true);
    messagingTemplate.convertAndSendToUser(destinationSessionId, "/subscribe/private", message, headerAccessor.getMessageHeaders());
}

这样做,在会话中没有校长,我无法使用@SendToUser注释。