Java & Tomcat下pe:session与p:commandButton的会话超时异常问题
问题详情
- 全局会话超时配置为30分钟,代码中
maxInactiveInterval设为30*60,配置无冲突 - 短时间测试(会话超时1分钟,
reactionPeriod设为50秒)时,按钮刷新、会话续期功能完全正常 - 30分钟超时场景下出现异常:
- 会话到期前5分钟(即用户操作25分钟后)弹出警告对话框,符合预期
- 但若等待到到期前约2分钟时,点击对话框中的"Keep my session alive"按钮无响应,对话框持续显示;此时点击页面其他按钮直接跳转至认证页面
- 重新登录后,有时返回纯XML内容,有时回到原页面
- 对话框弹出后立即或1分钟内点击按钮,会话可正常续期
- 怀疑是Tomcat会话配置问题,但控制台无有效错误日志,短时间测试未复现异常
环境信息
- Apache Tomcat 9.0.97
- JDK 17.0.14+7
旧代码实现
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions" xmlns:h="http://xmlns.jcp.org/jsf/html"> <script type="text/javascript"> var stringViewExpiredUrl = "site/faces/viewExpired.xhtml"; var environmentUrl = (window.location.href).substring(0, (window.location.href).search('site')); function peSessionRedirect() { window.location.replace(environmentUrl + stringViewExpiredUrl); } </script> <pe:session id="peSession" onexpire="PF('sessionDialog').show();" onexpired="PF('sessionDialog').hide();peSessionRedirect();" reactionPeriod="300" multiWindowSupport="true" /> <p:dialog widgetVar="sessionDialog" header="Session Expiration Warning"> <h:form> <p> Your session is about to expire in <pe:timer widgetVar="peSessionTimer" timeout="1800" format="mm:ss" resetValues="true" singleRun="true" style="color: red;" /> minutes. </p> <p:commandButton value="Keep my session alive" onsuccess="PF('sessionDialog').hide();PF('peSessionTimer').currentTimeout = 1800" /> </h:form> </p:dialog> </ui:composition>
新代码实现(新增poll心跳机制)
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions" xmlns:h="http://xmlns.jcp.org/jsf/html"> <pe:session id="peSession" onexpire="PF('sessionDialog').show();" reactionPeriod="300" multiWindowSupport="true" /> <p:dialog widgetVar="sessionDialog" header="Session Expiration Warning" onShow="PF('pollPing').start()" onHide="PF('pollPing').stop()"> <h:form> <p> Your session is about to expire in <pe:timer widgetVar="peSessionTimer" timeout="1800" format="mm:ss" ontimercomplete="PF('sessionDialog').hide();logoutCommand();" singleRun="true" style="color: red;" /> minutes. </p> <p:poll autoStart="false" widgetVar="pollPing" interval="60" onactivated="console.log('Poll started Every 60')" /> <p:remoteCommand name="logoutCommand" action="#{securityManager.logout}" /> <p:commandButton value="Keep my session alive" onsuccess="PF('sessionDialog').hide();PF('peSessionTimer').currentTimeout = 1800" /> </h:form> </p:dialog> </ui:composition>
排查思路
Tomcat会话检查间隔的影响
Tomcat默认每隔1分钟检查一次过期会话(由context.xml中的checkInterval控制,单位毫秒),并非实时触发。当会话接近30分钟超时时间时,可能在检查周期内被提前清理。可以尝试将checkInterval调小(比如设为10000即10秒),观察是否能缓解提前超时的情况。PrimeFaces Extensions组件的计时偏差
pe:session的reactionPeriod设为300秒(5分钟),长时间运行下可能因为客户端JavaScript计时精度、浏览器休眠导致的计时偏差,提前触发警告。可以在客户端控制台添加日志,跟踪pe:session的计时逻辑,或者微调reactionPeriod为290秒,看是否匹配预期的触发时机。会话续期请求的有效性
点击"Keep my session alive"按钮时,若请求没有正确更新会话的最后访问时间,可能是请求未携带有效会话ID,或者服务器端未正确处理续期逻辑。可以在服务器端添加日志,记录每次请求的会话ID、最后访问时间,确认按钮点击是否成功触发会话续期。多窗口场景的会话同步问题
虽然配置了multiWindowSupport="true",但多窗口下可能存在会话状态不同步的问题。可以测试单窗口场景下是否复现异常,排除多窗口的干扰。Tomcat会话持久化/集群配置
如果启用了Tomcat的会话持久化(如PersistentManager)或集群环境,可能存在会话状态同步延迟,导致会话被提前清理。检查context.xml中的会话管理器配置,确认是否有不必要的持久化或集群配置。
内容的提问来源于stack exchange,提问作者9SMo2

