97

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

我的 webapp 有 spring 安全设置并使用 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) 导航到http://localhost:8080,使用 bob/test 或 jim/test 登录

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

4

5 回答 5

92

哦,client side no need to known about current user服务器会为你做的。

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

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

注意:使用queue, not topic, Spring 总是使用queuewithsendToUser

在客户端

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

解释

当任何 websocket 连接打开时,Spring 将为它分配一个session id(不是HttpSession,为每个连接分配)。当您的客户端订阅以 开头的频道时/user/,例如:/user/queue/reply,您的服务器实例将订阅一个名为queue/reply-user[session id]

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

Spring 将确定哪个session id映射到 user admin。例如:它找到了两个会话wsxedc123and thnujm456,Spring 会将其转换为 2 个目的地queue/reply-userwsxedc123and queue/reply-userthnujm456,并将带有 2 个目的地的消息发送到您的消息代理。

消息代理接收消息并将其提供回您的服务器实例,该实例持有与每个会话对应的会话(WebSocket 会话可以由一个或多个服务器持有)。Spring 会将消息翻译为destination(eg: user/queue/reply) 和session id(eg: wsxedc123)。然后,它将消息发送到相应的Websocket session

于 2015-07-23T02:24:01.980 回答
36

啊,我发现我的问题是什么。首先我没有/user在简单代理上注册前缀

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

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

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

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

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

stompClient.subscribe('/user/' + userName + '/reply,...) 
于 2014-03-13T02:18:52.433 回答
3

我也使用 STOMP 创建了一个示例 websocket 项目。我注意到的是

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/getfeeds").withSockJS();
}

}

无论“/user”是否包含在 config.enableSimpleBroker(...

于 2016-04-02T20:56:35.957 回答
2

正是我做了同样的事情,它在不使用用户的情况下工作

@Configuration
@EnableWebSocketMessageBroker  
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
       registry.addEndpoint("/gs-guide-websocket").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic" , "/queue");
        config.setApplicationDestinationPrefixes("/app");
    }
}
于 2017-10-31T13:11:11.280 回答
2

我的解决方案基于 Thanh Nguyen Van 的最佳解释,但此外我还配置了 MessageBrokerRegistry:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/queue/", "/topic/");
        ...
    }
    ...
}
于 2015-08-31T14:36:33.143 回答