Vaadin 14推送模式导致HTTP会话无法失效的问题咨询
Vaadin 14 WebSocket心跳导致会话无法失效的解决方案
调整Push心跳间隔至超过会话超时时间
Vaadin默认Push心跳间隔为300秒(5分钟),会持续刷新HTTP会话状态,导致maxInactiveInterval设置失效。可通过配置将心跳间隔调至大于会话超时时长(比如35分钟):
- 在Spring Boot的
application.properties中添加配置:
注:单位为秒,2100秒=35分钟,需确保该值大于vaadin.push.heartbeat.interval=2100maxInactiveInterval的设置(30分钟=1800秒)。
按需启用Push模式
避免全局开启Push导致所有页面维持WebSocket连接,仅在需要后台非阻塞加载的视图上启用Push:
- 在对应的视图类上添加
@Push注解,而非全局配置:
其他无需后台加载的视图不添加该注解,对应的WebSocket连接不会建立,会话可正常超时。@Push @Route("async-view") public class AsyncLoadingView extends VerticalLayout { // 视图逻辑 }
前端手动控制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心跳请求,仅基于实际操作时间判断会话是否超时:
- 创建会话监听器记录用户最后实际操作时间:
@WebListener public class UserActivitySessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { se.getSession().setAttribute("lastUserActivity", System.currentTimeMillis()); } } - 拦截所有请求,仅在非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); } } - 添加定时任务检查会话,超时则销毁:
@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
相关产品推荐
相关产品推荐

