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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:37:32