嵌入式Jetty WebSocket服务器非根上下文配置失效问题求助
问题分析
你的核心问题出在上下文匹配顺序和WebSocket映射路径两个关键点:
- 当WebSocket Servlet放在根上下文
/时,它会优先匹配所有请求,导致后续的/*上下文DefaultServlet完全无法被触发。 - 改成
/ws上下文后,WebSocket的映射配置和客户端请求路径不匹配,进而导致连接失败。
解决方案
调整上下文配置顺序与WebSocket映射规则,修改后的完整代码如下:
public WebsocketServer(int port, Model model, SessionManager sessionManager) throws Exception { Server server = new Server(port); server.setRequestLog((request, response) -> log_.info("request {}", request)); ContextHandlerCollection handlers = new ContextHandlerCollection(); ServletContextHandler sch; // /model 上下文 - 保持原有逻辑不变 sch = new ServletContextHandler(); sch.setContextPath("/model"); sch.addServlet(new ServletHolder(new ModelServlet(model)), "/"); sch.setResourceBase("cfg"); handlers.addHandler(sch); // /web 上下文 - 保持原有逻辑不变 sch = new ServletContextHandler(); sch.setContextPath("/web"); sch.addServlet(DefaultServlet.class, "/*"); sch.setResourceBase("cfg"); sch.setWelcomeFiles(new String[]{"websocket.html"}); handlers.addHandler(sch); // /ws 上下文 - 修正映射配置 sch = new ServletContextHandler(); sch.setContextPath("/ws"); // 设置为目标/ws上下文 Servlet websocketServlet = new JettyWebSocketServlet() { @Override protected void configure(JettyWebSocketServletFactory factory) { // 映射上下文内所有路径,匹配客户端的ws://localhost:8080/ws请求 factory.addMapping("/*", (req, res) -> { Session s = new Session(req); sessionManager.add(s); return s; }); } }; // 将Servlet映射覆盖整个/ws上下文 sch.addServlet(new ServletHolder(websocketServlet), "/*"); JettyWebSocketServletContainerInitializer.configure(sch, null); handlers.addHandler(sch); // 根上下文DefaultServlet - 放在最后处理未匹配的请求 sch = new ServletContextHandler(); sch.setContextPath("/"); // 改为标准根上下文 sch.addServlet(DefaultServlet.class, "/*"); sch.setResourceBase("cfg"); handlers.addHandler(sch); server.setHandler(handlers); server.start(); }
关键修改说明
WebSocket映射调整:
- 将Servlet映射从
"/"改为"/*",确保整个/ws上下文下的请求都能被WebSocket Servlet处理。 - 将
factory.addMapping("/")改为factory.addMapping("/*"),匹配客户端发起的ws://localhost:8080/ws请求。
- 将Servlet映射从
上下文顺序优化:
- 把具体路径的上下文(
/model、/web、/ws)放在前面,根上下文的DefaultServlet放在最后,这样只有当请求不匹配前面的具体路径时,才会触发DefaultServlet,避免被前置上下文覆盖。
- 把具体路径的上下文(
根上下文修正:
- 将原来的
"/*"上下文改为标准的"/"根上下文,符合Jetty的上下文匹配规则。
- 将原来的
验证逻辑
客户端使用ws://localhost:8080/ws连接WebSocket时,请求会被/ws上下文的WebSocket Servlet处理;访问http://localhost:8080/web可正常加载网页,http://localhost:8080/model能正常访问ModelServlet,未匹配的请求则由根上下文的DefaultServlet处理。
内容的提问来源于stack exchange,提问作者Gord
相关产品推荐
相关产品推荐

