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

如何通过事件监听器拦截Jetty服务器的请求与响应并记录日志?

解决Jetty全请求/响应日志覆盖(含解析失败请求)的方案

要捕获所有传入请求(包括那些因解析错误无法到达业务Handler的请求)和响应,Jetty提供了几种可靠的方案,完全不需要手动在所有Handler里加日志:

1. 用Jetty内置的RequestLogHandler(最省心)

这是官方推荐的全请求日志方案,能自动记录所有请求——哪怕是像你遇到的URI空段导致的400错误请求,因为它在连接初始化阶段就开始追踪请求生命周期了。

配置示例(Java代码)

Server server = new Server();

// 创建RequestLogHandler
RequestLogHandler requestLogHandler = new RequestLogHandler();
NCSARequestLog requestLog = new NCSARequestLog("./logs/yyyy_mm_dd.request.log");
requestLog.setRetainDays(90);
requestLog.setAppend(true);
requestLog.setExtended(true);
requestLog.setLogTimeZone("GMT");
requestLogHandler.setRequestLog(requestLog);

// 将RequestLogHandler作为最外层Handler,包裹你的业务Handler链
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{yourBusinessHandler, requestLogHandler});
server.setHandler(handlers);

这个日志会自动记录请求方法、URI、状态码、响应大小、耗时等核心信息,包括解析失败返回的400状态。

2. 自定义底层监听器捕获解析阶段的请求

如果需要更灵活的自定义逻辑(比如记录原始请求头、错误栈),可以通过Jetty的底层连接监听器,捕获HttpParser解析失败的事件:

代码示例:监听HttpParser解析失败

server.addConnector(new ServerConnector(server) {
    @Override
    protected Connection newConnection(EndPoint endPoint, HttpConfiguration config) {
        HttpConnection connection = (HttpConnection) super.newConnection(endPoint, config);
        // 给HttpParser添加解析失败监听器
        connection.getHttpChannel().getHttpParser().addListener(new HttpParser.Listener() {
            @Override
            public void onBadMessage(BadMessageException failure) {
                // 记录解析失败的请求信息,比如从EndPoint获取远程地址
                String remoteAddr = endPoint.getRemoteAddress().toString();
                // 这里可以尝试读取原始请求数据(注意:解析失败时可能只能拿到部分数据)
                System.err.printf("解析失败请求 - 远程地址: %s, 错误: %s%n", remoteAddr, failure.getMessage());
            }

            @Override
            public void headerComplete() {
                // 请求头解析完成,此时可以拿到Request对象,提前记录
                Request request = connection.getHttpChannel().getRequest();
                System.out.printf("收到请求 - 方法: %s, URI: %s%n", request.getMethod(), request.getURI());
            }
        });
        return connection;
    }
});

这个方式能在请求解析出错的第一时间捕获到事件,哪怕Request对象还没完全初始化,也能记录错误原因和客户端信息。

3. 调整URI解析严格性(可选,谨慎使用)

如果你的业务允许空段URI(比如//quests/195),可以通过修改HttpConfiguration关闭严格模式,让请求能到达业务Handler:

HttpConfiguration httpConfig = new HttpConfiguration();
// 允许URI中的空段
httpConfig.setAllowEmptySegments(true);
// 或者关闭整体严格模式
// httpConfig.setStrictMode(false);

ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
server.addConnector(connector);

但注意:关闭严格模式可能引入安全风险,只有在明确业务需求且做过安全评估后再使用。

为什么你之前的日志没捕获到?

你遇到的BadMessageException是在HttpParser解析请求头阶段抛出的,此时请求还没进入业务Handler链,所以你在业务Handler里加的日志根本不会执行。必须用Jetty底层的监听器或RequestLogHandler才能覆盖这类场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:10:55