ShinyProxy集成Keycloak+Nginx+R Shiny登出时出现UT015005错误
问题解决:ShinyProxy登出时UT015005错误
问题背景
环境为集成Keycloak、ShinyProxy与Nginx的R Shiny应用,用户执行登出操作时可正常跳转至登录页,但ShinyProxy日志中出现如下错误:
2025-03-06 12:59:44 2025-03-06T08:59:44.394Z INFO 1 --- [ XNIO-1 task-5] e.o.containerproxy.service.UserService : User logged out [user: testuser] 2025-03-06 12:59:44 2025-03-06T08:59:44.410Z ERROR 1 --- [ XNIO-1 task-5] io.undertow.servlet.request : UT015005: Error invoking method sessionDestroyed on listener class org.springframework.security.web.session.HttpSessionEventPublisher
临时方案(先停止Shiny应用再登出)因后续要禁用开发者导航栏不可行。
问题原因
该错误源于会话销毁时序冲突:当用户直接登出时,Shiny应用的WebSocket连接仍处于活跃状态,ShinyProxy销毁HttpSession时,Spring Security的HttpSessionEventPublisher监听器尝试处理已被部分释放的会话资源,导致调用失败。
解决方案
1. 配置ShinyProxy会话超时与资源清理
在application.yml中添加会话超时配置,确保会话销毁时资源被正确释放:
proxy: # 新增会话超时配置(单位:秒,示例为3600秒即1小时) session-timeout: 3600 # 调整心跳超时为合理值,避免僵尸会话 heartbeat-timeout: 3600 # 保留原有配置...
2. 优化自定义登出流程(适配应用内导航栏)
在R Shiny应用的自定义导航栏中,添加JavaScript代码,先关闭Shiny的WebSocket连接,再触发ShinyProxy的登出请求:
library(shiny) ui <- fluidPage( tags$script(HTML(' function customLogout() { // 关闭Shiny的WebSocket连接 if (window.Shiny && window.Shiny.shinyapp && window.Shiny.shinyapp.connection) { window.Shiny.shinyapp.connection.close(); } // 延迟触发登出,确保连接关闭完成 setTimeout(() => { window.location.href = "/logout"; }, 100); } ')), # 自定义导航栏示例 navbarPage( "自定义导航", tabPanel("首页"), navbarMenu( "账户", actionLink("logoutBtn", "登出", onclick = "customLogout()") ) ) ) server <- function(input, output, session) { # 服务器逻辑 } shinyApp(ui, server)
3. 修正OpenID配置的一致性问题
application.yml中auth-url和logout-url需保持内外网地址一致性,内部容器通信使用Docker网络名称keycloak:
proxy: openid: # 修正auth-url为内部容器地址(外部请求由Nginx转发) auth-url: keycloak:8080/auth/realms/shinyrealm/protocol/openid-connect/auth # 修正logout-url的内部调用地址 logout-url: keycloak:8080/auth/realms/shinyrealm/protocol/openid-connect/logout?id_token_hint=#{oidcUser.idToken.tokenValue}&post_logout_redirect_uri=http%3A%2F%2Flocalhost # 保留原有配置...
注:Nginx已配置/auth/路径转发,外部用户访问时会自动映射为localhost/auth/。
4. 调整Nginx的WebSocket连接管理
在Nginx的location /块中,添加WebSocket存活检测配置,主动清理失效连接:
location / { proxy_pass http://shinyproxy:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Prefix /; # WebSocket支持增强 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600; # 新增:开启WebSocket长连接检测 proxy_socket_keepalive on; }
验证方法
- 重启所有容器:
docker-compose down && docker-compose up -d - 登录应用后直接点击自定义导航栏的登出按钮
- 查看ShinyProxy日志,确认UT015005错误不再出现
内容的提问来源于stack exchange,提问作者Reaperz Reaperz
相关产品推荐
相关产品推荐

