Jetty 11版本中CustomAbstractHandler修改HttpField无效问题排查求助
让我们一步步拆解你的代码里的问题:
1. 核心问题:自定义Handler被完全覆盖,根本没执行
看你的主类代码,你先给服务器设置了CustomAbstractHandler:
server.setHandler(new CustomAbstractHandler());
但紧接着你又设置了contextHandler作为服务器的根Handler:
server.setHandler(contextHandler);
Jetty的server.setHandler()方法会直接替换掉之前设置的所有Handler,也就是说你的CustomAbstractHandler根本不会被任何请求触发,修改请求头的代码自然不可能生效。
2. 次要问题:即使Handler生效,头修改可能无法同步到Servlet层
假设你修复了Handler覆盖的问题,还有一个潜在问题:Jetty内部的baseRequest(org.eclipse.jetty.server.Request)和Servlet规范的HttpServletRequest对象的头信息并不是自动双向同步的。你修改了baseRequest的HttpFields,但后续处理WebSocket的代码可能是通过HttpServletRequest获取头信息,这时候修改不会被感知到。
修复步骤
第一步:正确添加自定义Handler到Handler链
你需要把CustomAbstractHandler和contextHandler组合起来,让它们都能参与请求处理。Jetty提供了HandlerList来组合多个Handler:
// 替换原来两次setHandler的代码 HandlerList handlerList = new HandlerList(); handlerList.addHandler(new CustomAbstractHandler()); handlerList.addHandler(contextHandler); server.setHandler(handlerList);
这样请求会先经过CustomAbstractHandler处理,再传递给contextHandler处理WebSocket相关逻辑。
第二步:确保请求头修改能被后续逻辑读取
如果你的WebSocket处理依赖HttpServletRequest的头信息,仅修改baseRequest的HttpFields可能不够。这时候可以选择两种方式:
方式一:在更早的阶段修改请求头(推荐)
在请求进入Handler层之前,通过HttpConfiguration.Customizer修改请求头,这个阶段修改的头信息会被所有后续逻辑(包括WebSocket升级检查)读取到:
// 创建HttpConfiguration并添加自定义器 HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.addCustomizer(new HttpConfiguration.Customizer() { @Override public void customize(Connector connector, HttpConfiguration channelConfig, Request request) { // 修改Connection头为Upgrade HttpFields.Mutable mutableFields = request.getHttpFields().asMutable(); mutableFields.put("Connection", "Upgrade"); } }); // 使用带自定义HttpConfiguration的Connector ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); // 保留你原来的Connector配置 connector.setIdleTimeout(1000 * 60 * 60); connector.setPort(56667); // ...其他Connector配置 server.addConnector(connector);
方式二:在Handler中包装HttpServletRequest
如果你必须在Handler层修改,可以用HttpServletRequestWrapper包装请求,重写头相关方法:
@Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // 修改baseRequest的头 HttpFields.Mutable replacement = HttpFields.build(baseRequest.getHttpFields()).put("Connection", "Upgrade"); baseRequest.setHttpFields(replacement); LOG.info("" + baseRequest.getHttpFields()); // 包装HttpServletRequest,让后续逻辑读到修改后的头 HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(request) { @Override public String getHeader(String name) { if ("Connection".equalsIgnoreCase(name)) { return "Upgrade"; } return super.getHeader(name); } @Override public Enumeration<String> getHeaders(String name) { if ("Connection".equalsIgnoreCase(name)) { return Collections.enumeration(Collections.singletonList("Upgrade")); } return super.getHeaders(name); } }; // 传递包装后的请求给下一个Handler,不要标记为已处理 baseRequest.setHandled(false); nextHandle(target, baseRequest, wrappedRequest, response); }
注意这里要把baseRequest.setHandled(true)改成false,否则请求会被终止,不会传递到WebSocket的处理逻辑。
内容的提问来源于stack exchange,提问作者santhosh

