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

JVx Vaadin UI应用会话超时配置咨询:浏览器关闭即触发超时

解决方案:JVx + Vaadin 实现浏览器关闭即会话超时

首先明确:原生Servlet会话机制无法直接感知浏览器窗口/关闭事件,因为HTTP是无状态协议。要实现你要的效果,得结合前端心跳保活+关闭事件主动销毁会话+后端会话超时兜底三个部分来做,适配JVx和Vaadin的特性:

1. 调整web.xml的会话超时兜底配置

把原来的session-timeout改成一个较短的时间(比如1分钟),这样如果前端心跳中断(比如浏览器关闭),会话会快速超时:

<session-config>
    <session-timeout>1</session-timeout>
</session-config>

2. Vaadin前端添加心跳保活

在你的Vaadin UI类里,添加定时发送心跳请求的逻辑,只要浏览器标签打开,就每隔几十秒触发一次请求,保持会话活跃。可以用Vaadin的UI.access()和定时任务实现:

@Push
public class MainUI extends UI {
    private ScheduledExecutorService scheduler;

    @Override
    protected void init(VaadinRequest request) {
        // 初始化你的UI组件...

        // 启动心跳任务,每隔30秒发送一次请求
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(() -> {
            access(() -> {
                // 发送空请求触发会话刷新
                getPage().executeJavaScript("fetch('/heartbeat', {method: 'POST', credentials: 'include'})");
            });
        }, 0, 30, TimeUnit.SECONDS);
    }

    @Override
    public void detach() {
        super.detach();
        // 销毁定时任务
        if (scheduler != null) {
            scheduler.shutdownNow();
        }
    }
}

同时在后端添加一个简单的心跳Servlet处理请求:

@WebServlet("/heartbeat")
public class HeartbeatServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 仅触发会话的lastAccessedTime更新,无需业务逻辑
        request.getSession();
        response.setStatus(HttpServletResponse.SC_OK);
    }
}

3. 监听浏览器关闭事件,主动销毁会话

在Vaadin的UI中添加beforeunload事件监听,当用户关闭窗口/标签时,发送请求通知后端销毁会话:

@Override
protected void init(VaadinRequest request) {
    // ... 其他初始化代码

    // 监听浏览器关闭事件
    getPage().executeJavaScript("window.addEventListener('beforeunload', function(e) {" +
        "fetch('/destroy-session', {method: 'POST', credentials: 'include', keepalive: true});" +
    "});");
}

然后添加销毁会话的Servlet:

@WebServlet("/destroy-session")
public class DestroySessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 立即销毁当前Servlet会话
        request.getSession().invalidate();
        response.setStatus(HttpServletResponse.SC_OK);
    }
}

4. 适配JVx的会话管理

因为JVx有自己的会话上下文(ISession),需要在销毁Servlet中同时清理JVx的会话:

@WebServlet("/destroy-session")
public class DestroySessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 销毁JVx会话
        ISession jvxSession = SessionContext.getSession();
        if (jvxSession != null) {
            jvxSession.close();
        }
        // 销毁Servlet会话
        request.getSession().invalidate();
        response.setStatus(HttpServletResponse.SC_OK);
    }
}

注意事项

  • 心跳间隔要小于web.xml设置的session-timeout,比如超时1分钟,心跳30秒一次,确保会话不会因无活动超时。
  • beforeunload事件在浏览器崩溃等极端情况可能不触发,此时web.xml的兜底超时会生效,避免会话残留。
  • 使用keepalive: true确保关闭窗口时请求能发送成功,避免因页面卸载导致请求被取消。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:28:26