如何通过spring websocket STOMP向特定订阅发送消息?

Posted

技术标签:

【中文标题】如何通过spring websocket STOMP向特定订阅发送消息?【英文标题】:How to send message to a specific subscription over spring websocket STOMP? 【发布时间】:2020-03-02 12:00:24 【问题描述】:

我正在使用 STOMP over websockets with spring boot。是否有可能向特定订阅发送消息?我根据stomp documentation 使用包含 id 字段的 STOMP 标头订阅 STOMP 端点我希望此 id 用于确定应该接收消息的客户端,但 spring 似乎不使用这个身份证。我不能只使用 sendToUser 因为两个客户端可以具有相同的用户 ID,例如如果用户有两个打开的浏览器窗口。只有一个特定的窗口应该接收到消息。

在以下示例中,我有两个连接的客户端,它们使用相同的用户,但 STOMP 标头中的 id 不同。

Client1-ID:a32d66bf-03c7-47a4-aea0-e464c0727842

Client2-ID:b3673d33-1bf2-461e-8df3-35b7af07371b

在春季,我执行了以下 Kotlin 代码:

val subscriptions =  userRegistry.findSubscriptions 
            it.destination == "/user/topic/operations/$operationId/runs"
        
        subscriptions.forEach
            println("subscription id: $it.id");
            println("session id: $it.session.id");
            println("user id $it.session.user.name");
        

输出:

subscription id: sub-7
session id: mcjpgn2i
user id 4a27ef88-25eb-4175-a872-f46e7b9d0564
subscription id: sub-7
session id: 0dxuvjgp
user id 4a27ef88-25eb-4175-a872-f46e7b9d0564

没有我传递给 stomp 标头的 id 的迹象。

是否可以将消息发送到由我通过标头传递的 id 确定的特定订阅?

【问题讨论】:

【参考方案1】:

我让它工作了。

首先,我的客户端设置有问题。我在连接标头中设置了订阅 ID,如下所示:

this.stompClient.webSocketFactory = (): WebSocket => new SockJS("/ws");
this.stompClient.connectHeaders =  id: subscriptionId ;
this.stompClient.activate();

但是订阅头必须在订阅头中设置:

this.stompClient.subscribe(this.commonEndpoint,
        this.onMessageReceived.bind(this),
         id: subScriptionId );

如果我这样做,spring 会正确地使用这个 id 作为订阅 id,而不是使用像 sub-7 这样的默认值。

根据thread,我可以将消息发送到特定会话而不是用户。

使用以下代码,我可以向特定订阅发送消息:

val subscriptions = userRegistry.findSubscriptions 
            it.destination == "/user/topic/operations/$operationId/runs"
        
subscriptions.forEach 
    if(it.id === mySubscriptionId)
        val headerAccessor = 
        SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE)
        headerAccessor.sessionId = it.session.id
        headerAccessor.setLeaveMutable(true)

        simpMessagingTemplate.convertAndSendToUser(it.session.id,  
            "/topic/operations/runs", messageResponseEntity,
            headerAccessor.getMessageHeaders())

     

【讨论】:

我认为这段代码选择了一个“特定”订阅,好吧,但是然后向该订阅所属的会话(更像是用户级别,甚至连接级别)发送一条消息。因此,如果您在会话中有 sub-1 和 sub-2,则不能仅使用此代码向 sub-2 发送消息。所以它似乎适用于您的情况,因为您有两个 sub- 7s(如果 subs 都是 7 或不同的数字则无关紧要)但它们属于会话 mcjpgn2i 和 0dxuvjgp。相反,如果 subs 共享会话,则您将同时发送给两者。刚刚发布,因为我正试图让它也能正常工作......还没有运气!

以上是关于如何通过spring websocket STOMP向特定订阅发送消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过spring websocket STOMP向特定订阅发送消息?

对如何使用 Spring-websockets 进行 stomp 调用感到困惑

如何使用 SockJs 通过 STOMP Java 客户端验证 Spring 非 Web Websocket?

如何使用 Spring 和 Websocket 构建推送通知服务

如何将 spring-data-rest 与 spring websocket 混合到一个实现中

如何使用 Spring WebSocket 向 STOMP 客户端发送错误消息?