【问题标题】:WebSocket closed before HttpSessionListener.sessionDestroyed is calledWebSocket 在调用 HttpSessionListener.sessionDestroyed 之前关闭
【发布时间】:2016-06-21 18:18:39
【问题描述】:

我正在实现一个 Spring Boot + WebSocket + SockJS 应用程序,并且对如何处理 HTTP 会话/Websocket 关系有疑问。

基本上,我希望能够通知用户他的会话已失效(因为超时或从其他位置登录)。为此,我想在框架关闭之前将某个消息放入他自己的套接字中。

我转向了一个 http 侦听器,但我遇到的问题是,在调用 HttpSessionListener.sessionDestroyed() 时,我可以看到框架已经关闭了套接字(不是由于其他一些事件,例如用户关闭浏览器) .

有人知道如何实现这一目标吗?

我有一个非常简单的 Websocket 配置,并且使用 Spring Boot 默认值运行。

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.setMessageSizeLimit(10000000);
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app/");
    }

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

}

安全部分:

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        applySecurity(messages);
    }

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }

    private static void applySecurity(MessageSecurityMetadataSourceRegistry messages) {

        messages.nullDestMatcher().authenticated() //
                .simpDestMatchers("/app/**").authenticated().simpSubscribeDestMatchers("/user/reply").authenticated()
                .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll().anyMessage().denyAll();

    }
}  

我的 Http 监听器是这样的:

    return new HttpSessionListener() {

        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            simpMessagingTemplate.convertAndSendToUser(....);
        }

        @Override
        public void sessionCreated(HttpSessionEvent se) {
            // no need to do anything when a session is created
        }
    };

更新:

Spring-session 处理此类问题以及许多其他问题。

【问题讨论】:

    标签: java spring httpsession spring-websocket


    【解决方案1】:

    HttpSessionWebsocket 会话是两种不同类型的会话。 HttpSession 是在客户端访问 url 并完成握手时创建的,而 Websocket 会话是在客户端发送订阅请求时创建的。

    Websocket 会话被包裹在HttpSession 下。如果HttpSession 超时或失效,则底层Websocket 会话也会断开连接,但反之亦然。

    在您为Websocket 会话配置侦听器时,HttpSession 侦听器将无法侦听Websocket 会话事件。对于此类事件,我们需要定义一个扩展 org.springframework.web.socket.messaging.SubProtocolWebSocketHandler 类并覆盖 afterConnectionEstablishedafterConnectionClosed 方法的类。看看 Javadoc here

    另外,here 是一个监听 Spring websocket 断开事件的例子。你需要配置类似的东西。

    【讨论】:

    • 感谢您提供的信息,但我不确定我们是否在谈论相同的问题。我对监听的 websocket 会话事件不感兴趣,但对 http 会话事件不感兴趣。在 websocket 会话绑定到 http 会话的意义上,你是对的。从这个意义上说,我想通过 websocket 向用户发送一条消息,例如:“Hej,你的 http 会话即将失效,所以准备好......”在该消息之后,http 会话将失效,然后 websocket 将被关闭,但用户会知道原因。
    • 我不确定 spring 是否允许向特定会话发送消息,请查看此 SO 答案 (stackoverflow.com/questions/22367223/…)。另外,我认为不可能从 httpsession 获取 websocket 会话,除非我们按照该示例中的说明手动将会话 ID 映射存储在地图中。
    • 我向用户发送消息没有问题。问题是在调用 HttpsessionListener.sessiondestroyed 时,框架已经关闭了 Web 套接字,我不能再使用它了。文档说“收到会话即将失效的通知”,这意味着 http 会话仍然存在(网络套接字会话应该也是如此)但事实并非如此:网络套接字连接已经关闭。
    • 即将失效的 HTTP 会话并不意味着 Web 套接字应该仍然存在。
    • 好吧,两个会话都处于活动状态,当我使 http 会话无效时,websocket 会话似乎在调用 sessionDestroyed 之前关闭。有什么办法可以把东西挂在那里吗?我只想能够在网络套接字中放置一条“最终”消息。如果我没记错的话,是 Spring Security 关闭了 Web 套接字(可能通过 WebSocketHandlerDecoratorFactory)
    【解决方案2】:

    HTTP 会话应该在连接中继续存在。这就是它的用途。多个连接,同一个会话。存在活动连接时会话不应过期。

    【讨论】:

      猜你喜欢
      • 2019-12-14
      • 1970-01-01
      • 2020-10-21
      • 1970-01-01
      • 1970-01-01
      • 2018-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多