在Spring Websocket上向特定用户发送消息

2022-08-31 10:23:37

如何仅将websocket消息从服务器发送到特定用户?

我的 webapp 具有弹簧安全设置,并使用 websocket。我遇到了棘手的问题,试图从服务器仅向特定用户发送消息。

我从阅读手册中得到的理解是,从服务器我们可以做到

simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply);

在客户端:

stompClient.subscribe('/user/reply', handler);

但我永远无法调用订阅回调。我尝试过许多不同的道路,但没有运气。

如果我将其发送到/topic/reply,它可以工作,但所有其他连接的用户也将收到它。

为了说明这个问题,我在github上创建了这个小项目:https://github.com/gerrytan/wsproblem

重现步骤:

1)克隆并构建项目(确保你使用的是jdk 1.7和maven 3.1)

$ git clone https://github.com/gerrytan/wsproblem.git
$ cd wsproblem
$ mvn jetty:run

2) 导航到 ,使用 bob/test 或 jim/test 登录http://localhost:8080

3)单击“请求用户特定消息”。预期:“仅收到发送给我的消息”旁边显示消息“hello {username}”,仅针对此用户,实际:未收到任何内容


答案 1

哦,服务器会为你做到这一点。client side no need to known about current user

在服务器端,使用以下方式向用户发送消息:

simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message);

注意:使用队列,而不是主题,Spring总是将队列sendToUser一起使用

在客户端

stompClient.subscribe("/user/queue/reply", handler);

解释

当任何 websocket 连接处于打开状态时,Spring 会为其分配一个(而不是 按连接分配 )。当您的客户端订阅以 开始的通道时,例如:,您的服务器实例将订阅一个名为session idHttpSession/user//user/queue/replyqueue/reply-user[session id]

当使用发送消息给用户时,例如:用户名是你会写的adminsimpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

弹簧将确定哪个映射到用户。例如:它找到了两个会话,并且,Spring会将其转换为2个目的地,并将具有2个目的地的消息发送到您的消息代理。session idadminwsxedc123thnujm456queue/reply-userwsxedc123queue/reply-userthnujm456

消息代理接收消息并将其提供回服务器实例,该服务器实例保存与每个会话对应的会话(WebSocket 会话可以由一个或多个服务器保留)。Spring会将消息翻译成(例如:)和(例如:)。然后,它将消息发送到相应的destinationuser/queue/replysession idwsxedc123Websocket session


答案 2

啊,我发现了我的问题所在。首先,我没有在简单经纪人上注册前缀/user

<websocket:simple-broker prefix="/topic,/user" />

然后我在发送时不需要额外的前缀:/user

convertAndSendToUser(principal.getName(), "/reply", reply);

Spring将自动附加到目标之前,因此它解析为“/user/bob/reply”。"/user/" + principal.getName()

这也意味着在javascript中,我必须为每个用户订阅不同的地址。

stompClient.subscribe('/user/' + userName + '/reply,...) 

推荐