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

Jetty中WebSocketServlet无法读取HttpServlet设置的Session属性问题

问题根源分析

你遇到的核心问题是:两个独立的ServletContextHandler会维护各自独立的会话上下文。虽然你都开启了SESSIONS模式,但Jetty中每个ServletContextHandler默认会创建自己的SessionHandler和会话存储容器。这就导致HTTP请求和WebSocket请求看似使用同一个JSESSIONID Cookie,但实际对应的是两个完全隔离的会话对象——从你调试信息里的Session@24b04e4和Session@5989f3d1也能看出来,它们是不同的实例,自然共享不了属性。

解决方案

有两种靠谱的解决方式,任选其一即可:

方案1:给两个ServletContextHandler共用同一个SessionHandler

创建一个共享的SessionHandler实例,然后分别设置给HTTP和WebSocket的ServletContextHandler,让它们共用同一会话存储:

// 创建共享的SessionHandler
val sharedSessionHandler = SessionHandler()

// HTTP Handler配置
val httpHandler = object : ServletContextHandler(nullParent, contextPath, SESSIONS).apply {
    addServlet(ServletHolder(httpServlet), "/*")
    // 设置共享的SessionHandler
    sessionHandler = sharedSessionHandler
}

// WebSocket Handler配置
val webSocketHandler = object : ServletContextHandler(nullParent, contextPath, SESSIONS).apply {
    addServlet(ServletHolder(wsServlet), "/*")
    // 设置共享的SessionHandler
    sessionHandler = sharedSessionHandler
}

// 绑定到Server
server.handler = HandlerList(httpHandler, webSocketHandler)

方案2:合并为同一个ServletContextHandler

把HTTP Servlet和WebSocket Servlet注册到同一个ServletContextHandler下,通过不同的路径映射区分请求,这样它们天然共享同一会话上下文:

val combinedHandler = ServletContextHandler(nullParent, contextPath, SESSIONS).apply {
    // HTTP请求映射到根路径
    addServlet(ServletHolder(httpServlet), "/*")
    // WebSocket请求映射到/websocket路径
    addServlet(ServletHolder(wsServlet), "/websocket")
}

// 直接绑定合并后的Handler到Server
server.handler = combinedHandler

这种方式更简洁,也更符合Jetty的常规使用方式,推荐优先考虑。

补充说明

需要注意的是,如果你保留原来的HandlerList方式,一定要确保HTTP Handler在检测到WebSocket升级请求时正确返回,让请求流转到WebSocket Handler——不过方案2已经不需要这种判断了,因为路径映射会直接区分请求归属。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 00:47:42