web-dev-qa-db-ja.com

Spring websocketストンプサーバーからクライアントセッションを切断する

私はかなり検索しましたが、これを見つけることができませんでした:Spring WebSocketストンプサーバーが、SessionIdに基づいて(または実際に何かに基づいて)クライアントを切断できる方法はありますか?

いったんクライアントがサーバーに接続すると、サーバーがクライアントを切断できるようにするものは何もないように思えます。

23
user1751547

私が知る限り、APIが探しているものを提供しない場合、サーバー側では切断イベントのみを検出できます。特定のクライアントを切断したい場合は、少し回避策をとる必要があると思います。これです:

  1. 切断をトリガーできるクライアント側のJavaScript関数を作成する
  2. クライアントがサーバーに接続されるとすぐに、JavaScriptでクライアントIDを生成し、サーバーに送信します。クライアントのIDを覚えておいてください。ステップ(4)で必要になります。
  3. サーバーに特定のクライアント(IDで識別される)への接続を切断させたいときに、IDを含むメッセージをクライアントに送信します。
  4. これで、クライアントのJavaScriptがサーバーから送信されたメッセージを評価し、手順(1)で記述した切断関数を呼び出すことを決定します。
  5. クライアントは自身を切断します。

回避策は少し面倒ですが、うまくいきます。

3
mika

実際にいくつかの回避策を使用すると、必要なことを達成できます。そのためにあなたはすべきです:

  1. Java構成を使用します(XML構成で可能かどうかは不明です)
  2. WebSocketMessageBrokerConfigurationSupportから構成クラスを拡張し、WebSocketMessageBrokerConfigurerインターフェースを実装します
  3. カスタムサブプロトコルwebsocketハンドラーを作成し、SubProtocolWebSocketHandlerクラスから拡張します
  4. カスタムサブプロトコルwebsocketハンドラーでオーバーライドafterConnectionEstablishedメソッドを使用すると、WebSocketSessionにアクセスできます:)

クライアント側のセッションをサーバー側から切断する方法を示すサンプルSpring-Bootプロジェクトを作成しました: https://github.com/isaranchuk/spring-websocket-disconnect

17
isaranchuk

カスタム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();
    }
}
5
Dániel Kis

まず、継承によってクラスをUserクラスとして導入し、次のように使用する必要があります。

if (userObject instanceof User) {
    User user = (User) userObject;
    if (user.getId().equals(userDTO.getId())) {
       for (SessionInformation information : sessionRegistry.getAllSessions(user, true)) {
          information.expireNow();
       }
    }
}    
1
Charlie873

Xml構成の場合、<websocket:decorator-factories><websocket:transport><websocket:message-broker>を使用できます。 WebSocketHandlerDecoratorメソッドを実装するカスタムWebSocketHandlerDecoratorFactoryおよびdecorateを作成します。

0

これは簡単に見えるかもしれませんが、あなたの場合の実装がどのようになるかはわかりません。しかし、私はこの回避策/解決策を保証するいくつかの状況があると思います:

  1. バックエンドにタイムアウトを設定します(たとえば30秒):
    • これは、Spring Boot Websocket(およびTomcat)でそれを行う方法です。
    @Bean
    public ServletServerContainerFactoryBean websocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        container.setMaxSessionIdleTimeout(MAX_SESSION_IDLE_TIMEOUT); 
        return container;
    }
  1. セッションを開いたままにしたい場合は、引き続きメッセージを送信するか、アクティブにping /ポングを送信してください。セッションを切断したい場合は、アプリケーションに適した場所でping/pongの対話を停止してください。

もちろん、すぐに切断したい場合、これは適切な解決策ではないようです。ただし、アクティブな接続の数を減らすだけの場合は、メッセージがアクティブに送信されている間だけセッションを開いたままにし、セッションが途中で閉じられるのを防ぐため、ping/pongが適しています。

0
Christian Meyer