从Spring websocket stomp服务器断开客户端会话

use*_*547 21 spring stomp spring-boot spring-websocket

我已经搜索了很多并且无法找到这个:有没有办法让一个spring websocket stomp服务器可以根据sessionId断开客户端(或者真的基于任何东西)?

在我看来,一旦客户端连接到服务器,没有任何东西允许服务器断开客户端.

isa*_*huk 15

实际上使用一些解决方法,您可以实现您想要的.为此你应该这样做:

  1. 使用java配置(不确定是否可以使用XML配置)
  2. WebSocketMessageBrokerConfigurationSupport扩展您的配置类并实现WebSocketMessageBrokerConfigurer接口
  3. 创建自定义子协议websocket处理程序并从SubProtocolWebSocketHandler类扩展它
  4. 在您的自定义子协议中,websocket处理程序覆盖afterConnectionEstablished方法,您将可以访问WebSocketSession :)

我已经创建了示例spring-boot项目,以展示我们如何从服务器端断开客户端会话:https: //github.com/isaranchuk/spring-websocket-disconnect

  • 应该接受此响应,它无需客户合作即可工作 (2认同)

Dán*_*Kis 5

您还可以通过实现自定义来断开会话WebSocketHandlerDecorator

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig<S extends ExpiringSession> extends AbstractSessionWebSocketMessageBrokerConfigurer<S> {

    @Override
    public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
        registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
            @Override
            public WebSocketHandler decorate(final WebSocketHandler handler) {
                return new WebSocketHandlerDecorator(handler) {
                    @Override
                    public void afterConnectionEstablished(final WebSocketSession session) throws Exception {

                        session.close(CloseStatus.NOT_ACCEPTABLE);
                        super.afterConnectionEstablished(session);
                    }
                };
            }
        });
        super.configureWebSocketTransport(registration);
    }


    @Override
    protected void configureStompEndpoints(final StompEndpointRegistry registry) {
    registry.addEndpoint("/home")
            .setHandshakeHandler(new DefaultHandshakeHandler(
                    new UndertowRequestUpgradeStrategy() // If you use undertow
                    // new JettyRequestUpgradeStrategy()
                    // new TomcatRequestUpgradeStrategy()
            ))
            .withSockJS();
    }
}
Run Code Online (Sandbox Code Playgroud)


Rus*_*lin 5

我依靠 @D\xc3\xa1niel Kis 的想法,实现了 websocket 会话管理,其关键点是在类似 Singleton 的对象中为经过身份验证的用户存储 websocket 会话。

\n
// WebSocketConfig.java\n\n@Configuration\n@EnableWebSocketMessageBroker\npublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer {\n\n    @Override\n    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {\n        registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {\n            @Override\n            public WebSocketHandler decorate(final WebSocketHandler handler) {\n                return new WebSocketHandlerDecorator(handler) {\n\n                    @Override\n                    public void afterConnectionEstablished(final WebSocketSession session) throws Exception {\n\n                        // We will store current user's session into WebsocketSessionHolder after connection is established\n                        String username = session.getPrincipal().getName();\n                        WebsocketSessionHolder.addSession(username, session);\n\n                        super.afterConnectionEstablished(session);\n                    }\n                };\n            }\n        });\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

存储 websocket 用户会话的类WebsocketSessionHolder。我使用“同步”块来保证线程安全。实际上,这个块并不是昂贵的操作,因为每个方法(addSession 和 closeSessions)都不经常使用(在建立和终止连接时)。这里不需要使用 ConcurrentHashMap 或 SynchronizedMap,因为我们在这些方法中对列表执行了一堆操作。

\n
// WebsocketSessionHolder.java\n\npublic class WebsocketSessionHolder {\n\n    static {\n        sessions = new HashMap<>();\n    }\n    \n    // key - username, value - List of user's sessions\n    private static Map<String, List<WebSocketSession>> sessions;\n\n    public static void addSession(String username, WebSocketSession session)\n    {\n        synchronized (sessions) {\n            var userSessions = sessions.get(username);\n            if (userSessions == null)\n                userSessions = new ArrayList<WebSocketSession>();\n\n            userSessions.add(session);\n            sessions.put(username, userSessions);\n        }\n    }\n\n    public static void closeSessions(String username) throws IOException \n    {\n        synchronized (sessions) {\n            var userSessions = sessions.get(username);\n            if (userSessions != null)\n            {\n                for(var session : userSessions) {\n                    // I use POLICY_VIOLATION to indicate reason of disconnecting for a client\n                    session.close(CloseStatus.POLICY_VIOLATION);\n                }\n                sessions.remove(username);\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

最后一步 - 终止(断开连接)指定的用户 websocket 会话(示例中的“ADMIN”),例如在某些控制器中

\n
//PageController.java\n\n@Controller\npublic class PageController {\n    @GetMapping("/kill-sessions")\n    public void killSessions() throws Exception {\n\n        WebsocketSessionHolder.closeSessions("ADMIN");\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


mik*_*ika 3

据我所知,API 不提供您正在寻找的内容,在服务器端您只能检测断开连接事件。如果您想断开某个客户端的连接,我认为您必须采取一些解决方法,例如:

  1. 编写一个能够触发断开连接的客户端 JavaScript 函数
  2. 一旦您的客户端连接到服务器,请在 JavaScript 中生成客户端 ID 并将其发送到服务器。请记住客户端上的 ID,您将在步骤 (4) 中需要它。
  3. 当您希望服务器断开与特定客户端(由 ID 标识)的连接时,将包含 ID 的消息发送回客户端。
  4. 现在,您的客户端 JavaScript 评估从服务器发送的消息,并决定调用您在步骤 (1) 中编写的断开连接函数。
  5. 您的客户端会自行断开连接。

解决方法有点麻烦,但它会起作用。

  • 不幸的是,这假设客户端遵守断开连接消息。最终我不希望客户有发言权。标记为答案,因为这似乎不可能。 (9认同)
  • 根据 `SubProtocolWebSocketHandler.java` 的 `afterConnectionEstablished()` 方法的源代码,可以看到: `// WebSocketHandlerDecorator 可以关闭会话` (2认同)