Jetty Client 11如何实现单请求维度的收发字节数统计
Jetty Client 11 单请求字节统计(含请求/响应头)实现方案
之前方案的问题定位
ConnectionStatistics方案失效原因:- 它是连接级累计统计组件,统计的是整个TCP连接从建立到关闭的所有字节(含所有复用该连接的请求),而非单请求维度。
- 你在
request.send()后立即取统计值,此时请求刚发起,连接的字节传输事件尚未触发;且keep-alive场景下请求结束后连接不关闭,统计值不会更新,因此始终返回0。
onRequestContent方案GET请求统计为0的原因:- 该钩子仅在请求有内容体时触发,GET请求无请求体,因此永远不会触发。
- 即使有请求体,该钩子也只统计请求体片段,不包含请求行、请求头的字节量。
正确实现方案(适配HTTP/2 GET请求)
核心逻辑:监听请求的所有报文序列化/反序列化事件(含头、体),而非仅监听内容体事件,用线程安全容器累加单请求的字节数。
// 单请求字节统计容器(线程安全) class RequestByteCounter { final AtomicLong sentBytes = new AtomicLong(0); final AtomicLong receivedBytes = new AtomicLong(0); } // 初始化HTTP/2 HttpClient(按Jetty 11规范配置,此处略去启动逻辑) HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2()); httpClient.start(); // 发起单请求并绑定统计 RequestByteCounter counter = new RequestByteCounter(); httpClient.newRequest("https://target-uri") .version(HttpVersion.HTTP_2) // 1. 统计请求行+请求头的发送字节(HTTP/2为HPACK压缩后的载荷,用Jetty内置生成器计算) .onRequestHeaders(req -> { HttpGenerator generator = new HttpGenerator(); ByteBuffer headerBuf = ByteBuffer.allocate(2048); generator.generateRequest( req.getMethod(), req.getRequestURI(), req.getVersion(), req.getHeaders(), null, // 无Trailers 0, // 无请求体(GET场景) headerBuf ); counter.sentBytes.addAndGet(generator.getPreparedBytes()); }) // 2. 统计请求体发送字节(GET请求无此步,仅POST/PUT等有体请求触发) .onRequestContent((req, buf) -> counter.sentBytes.addAndGet(buf.remaining())) // 3. 统计响应状态行+响应头的接收字节 .onResponseHeaders(res -> { // 计算HTTP/2伪头(:status)+ 普通响应头的字节数 int headerSize = 0; headerSize += (":status: " + res.getStatus() + "\r\n").getBytes(StandardCharsets.UTF_8).length; for (HttpField field : res.getHeaders()) { headerSize += (field.getName() + ": " + field.getValue() + "\r\n").getBytes(StandardCharsets.UTF_8).length; } headerSize += 2; // 头终止符\r\n counter.receivedBytes.addAndGet(headerSize); }) // 4. 统计响应体接收字节(你之前的已验证方案) .onResponseContent((res, buf) -> counter.receivedBytes.addAndGet(buf.remaining())) // 请求完成后输出统计值 .send(new BufferingResponseListener() { @Override public void onComplete(Result result) { System.out.printf("单请求发送字节: %d, 接收字节: %d%n", counter.sentBytes.get(), counter.receivedBytes.get()); } });
补充说明
- 若需要实际网络传输的HPACK压缩后字节数(而非应用层未压缩字节),需绑定当前Stream的
HPACK.Decoder/Encoder实例,监听其输出字节数。 - 若使用HTTP/1.1,可简化为请求前后连接级统计差值(因HTTP/1.1连接串行,无并发复用干扰)。
内容的提问来源于stack exchange,提问作者pmpm
相关产品推荐
相关产品推荐

