You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vaadin 14推送模式导致HTTP会话无法失效的问题咨询

Vaadin 14 WebSocket心跳导致会话无法失效的解决方案

调整Push心跳间隔至超过会话超时时间

Vaadin默认Push心跳间隔为300秒(5分钟),会持续刷新HTTP会话状态,导致maxInactiveInterval设置失效。可通过配置将心跳间隔调至大于会话超时时长(比如35分钟):

  • 在Spring Boot的application.properties中添加配置:
    vaadin.push.heartbeat.interval=2100
    
    注:单位为秒,2100秒=35分钟,需确保该值大于maxInactiveInterval的设置(30分钟=1800秒)。

按需启用Push模式

避免全局开启Push导致所有页面维持WebSocket连接,仅在需要后台非阻塞加载的视图上启用Push:

  • 在对应的视图类上添加@Push注解,而非全局配置:
    @Push
    @Route("async-view")
    public class AsyncLoadingView extends VerticalLayout {
        // 视图逻辑
    }
    
    其他无需后台加载的视图不添加该注解,对应的WebSocket连接不会建立,会话可正常超时。

前端手动控制WebSocket连接关闭

监听用户前端活动,当检测到用户长时间无操作(接近30分钟)时,主动关闭Push连接,停止心跳:

  • 在视图中注入JavaScript监听用户活动,并在超时后关闭Push:
    @Route
    public class MainView extends VerticalLayout {
        public MainView() {
            getElement().executeJs("""
                let lastActivity = Date.now();
                window.addEventListener('mousemove', () => lastActivity = Date.now());
                window.addEventListener('keydown', () => lastActivity = Date.now());
                
                setInterval(() => {
                    if (Date.now() - lastActivity > 1740000) { // 29分钟=1740000毫秒
                        if (Vaadin.Push && Vaadin.Push.close) {
                            Vaadin.Push.close();
                        }
                    }
                }, 60000); // 每分钟检查一次
            """);
        }
    }
    

自定义会话超时逻辑,忽略Push心跳

在服务器端区分用户实际操作与Push心跳请求,仅基于实际操作时间判断会话是否超时:

  1. 创建会话监听器记录用户最后实际操作时间:
    @WebListener
    public class UserActivitySessionListener implements HttpSessionListener {
        @Override
        public void sessionCreated(HttpSessionEvent se) {
            se.getSession().setAttribute("lastUserActivity", System.currentTimeMillis());
        }
    }
    
  2. 拦截所有请求,仅在非Push心跳请求时更新最后操作时间:
    @Component
    public class UserActivityFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            String path = request.getRequestURI();
            // 排除Vaadin Push的心跳请求路径
            if (!path.contains("/VAADIN/push")) {
                request.getSession().setAttribute("lastUserActivity", System.currentTimeMillis());
            }
            filterChain.doFilter(request, response);
        }
    }
    
  3. 添加定时任务检查会话,超时则销毁:
    @Component
    public class SessionTimeoutChecker {
        @Autowired
        private ServletContext servletContext;
    
        @Scheduled(fixedRate = 60000) // 每分钟检查一次
        public void checkInactiveSessions() {
            long currentTime = System.currentTimeMillis();
            long timeoutMillis = 1800000; // 30分钟=1800000毫秒
    
            for (HttpSession session : Collections.list(servletContext.getServletContext().getSessions())) {
                long lastActivity = (long) session.getAttribute("lastUserActivity");
                if (currentTime - lastActivity > timeoutMillis) {
                    session.invalidate();
                }
            }
        }
    }
    

内容的提问来源于stack exchange,提问作者Benedikt Schmidt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 00:47:31