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

如何使用AsyncHttpClient正确度量HTTP请求各阶段耗时

结论先行
  • onRequestSend完全不适合作为请求起始时间的判定依据
  • 你要找的「客户端侧创建socket发起连接动作」对应的事件是onTcpConnectAttempt;如果要覆盖DNS解析全流程,整个网络请求生命周期的第一个触发事件是onDnsResolutionAttempt

为什么onRequestSend不能用

onRequestSend的触发时机非常晚:只有当AHC拿到了可用连接(要么是连接池里复用的已有长连接,要么是已经走完DNS解析、TCP握手、HTTPS握手的全新连接),开始往网络通道写HTTP请求报文的时候,才会触发这个事件。
拿它当起始点会出两个致命问题:

  • 碰到连接池复用的场景,DNS、TCP建连、TLS握手这几个步骤根本不会执行,对应事件也不会触发,你算出来的这几个阶段耗时要么是0要么是负数,完全不准
  • 哪怕是新建连接的场景,这个事件触发的时候连接已经建完了,你根本统计不到前面DNS、TCP握手的耗时

各指标的正确时间点标记方法

你自定义实现AsyncHandler重写对应生命周期回调,在回调里打System.nanoTime()时间戳就行,各个指标的对应起止点列清楚:

  • 总响应耗时:如果要算用户视角的端到端耗时,就从你代码里调用executeRequest提交请求的那行开始记,结束点取onComplete或者onThrowable触发的时刻,这样连客户端内部排队、等连接池分配连接的时间都能覆盖到;如果只想算纯网络交互的耗时,就从onDnsResolutionAttempt触发开始记
  • DNS解析耗时:起点是onDnsResolutionAttempt触发时刻,终点是onDnsResolutionSuccess触发时刻
  • TCP连接耗时:起点就是你要找的onTcpConnectAttempt触发时刻(这时候客户端刚创建socket,开始发起TCP握手),终点是onTcpConnectSuccess触发时刻
  • TLS握手耗时(HTTPS场景):起点是onTlsHandshakeAttempt,终点是onTlsHandshakeSuccess
  • TTFB(首字节耗时):起点取onRequestSend触发时刻(刚开始往网络写请求),终点取onStatusReceived触发时刻(刚收到响应行和响应头),这个口径比等第一个body字节到更准
  • 请求发送耗时:onRequestSend到onRequestSent的时间差,就是整个请求报文完全写入网络的耗时

几个注意点

  • 连接复用场景下,DNS、TCP、TLS相关的attempt事件都不会触发,这几个阶段耗时直接记0就行,属于正常情况,不是bug
  • 记时间戳一律用System.nanoTime(),别用System.currentTimeMillis(),后者会受系统时间回拨影响,算出来的耗时可能出离谱的错
  • 如果要区分连接复用和新建连接的场景,你可以判断有没有触发过onTcpConnectSuccess事件,触发过就是新建连接,否则就是复用连接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:06:24