STOMP 规范规定订阅必须有id header。
https://stomp.github.io/stomp-specification-1.2.html#SUBSCRIBE_id_Header
SUBSCRIBE id Header
Since a single connection can have multiple open subscriptions with a server, an id header MUST be included in the frame to uniquely identify the subscription. The id header allows the client and server to relate subsequent MESSAGE or UNSUBSCRIBE frames to the original subscription. Within the same connection, different subscriptions MUST use different subscription identifiers.
然而,在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 header 。
我的问题是在给客户端发送消息时如何指定id header?
最佳答案
我认为您不能使用订阅 ID 向特定客户端发送消息。 Stomp 定义了这个 ID,Spring 的实现在内部使用它来为订阅目标地址的每个客户端创建消息。因此,订阅 ID 在 Stomp 通信中是透明的......您可以在客户端指定它或让 Stomp JS(STOMP Over WebSocket)创建一个唯一的。
如果您订阅以“/user/”为前缀的目标并使用 org.springframework.messaging.simp.SimpMessagingTemplate#convertAndSendToUser
或 org. springframework. messaging. simp . annotation.SendToUser
向单个客户端发送消息,Spring 所做的是根据原始目的地注册并创建对基于自定义 session 的目的地的订阅。换句话说,来自 Spring 的 Javadoc:
When a user attempts to subscribe, e.g. to "/user/queue/position-updates", the "/user" prefix is removed and a unique suffix added based on the session id, e.g. "/queue/position-updates-useri9oqdfzo" to ensure different users can subscribe to the same logical destination without colliding.
When sending to a user, e.g. "/user/{username}/queue/position-updates", the "/user/{username}" prefix is removed and a suffix based on active session id's is added, e.g. "/queue/position-updates-useri9oqdfzo".
编辑:
您不能使用订阅 ID 直接向其订阅的客户端发送消息,但可以使用客户端的 session ID。根据here ,您可以使用用户的姓名向他发送消息。但是您需要与 Principal 进行身份验证的 session 。或者您可以在消息的 header 中强制使用目标的 session 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());
}
这样做,如果 session 中没有 Principal,我将无法使用 @SendToUser
注释。
关于stomp - spring-websocket STOMP 是否支持 SUBSCRIBE id?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44857585/