HarmonyOS —— 基于 TracingConfiguration 做 HTTP 性能维测实战笔记

HarmonyOS —— 基于 TracingConfiguration 做 HTTP 性能维测实战笔记

前面折腾了 DNS / 传输 / 代理 / 安全 / 拦截器 / 流式传输,这一篇换个视角:
不改行为,只“看清楚”HTTP 每一步花了多少时间、数据是怎么流的。
也就是:基于 TracingConfiguration 做性能埋点 & 调试。


一、能力概览 & 设备支持

鸿蒙开发者第四期活动

TracingConfiguration 的作用:

  • 捕获一次 HTTP 请求 / 响应链路上的 详细事件 & 时间信息
  • 可按需打开不同级别的跟踪:
    • 是否输出详细日志(verbose
    • 收集哪些类型的信息事件(infoToCollect
    • 要不要采集时间信息(collectTimeInfo
    • HTTP 关键节点的回调处理(httpEventsHandler

设备支持:

  • 支持:Phone / 2in1 / Tablet / Wearable
  • 5.1.1(19) 起:新增 TV 支持

一句记:性能维测能力支持 Phone / 2in1 / Tablet / Wearable,5.1.1(19) 起支持 TV


二、用 TracingConfiguration 捕获请求 / 响应详细过程

1. HttpEventsHandler:拿到“数据 + 头 + 结束”的时刻

import { rcp } from '@kit.RemoteCommunicationKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 自定义 HTTP 事件处理器
const customHttpEventsHandler: rcp.HttpEventsHandler = {
  onDataReceive: (incomingData: ArrayBuffer) => {
    // 每收到一块响应 body 数据都会回调这里
    console.info('Received data:', JSON.stringify(incomingData));
    return incomingData.byteLength; // 返回处理的数据长度
  },
  onHeaderReceive: (headers: rcp.RequestHeaders) => {
    // 收到响应头时调用
    console.info('Received headers:', JSON.stringify(headers));
  },
  onDataEnd: () => {
    // 整个响应数据传输完成时
    console.info('Data transfer complete');
  }
};

可以用来做什么?

  • onHeaderReceive
    • 做响应头检查、埋点、根据 header 动态调整 UI;
  • onDataReceive
    • 边下边解码(比如流式 JSON、日志、视频分片等);
  • onDataEnd
    • 做「加载完成」打点,或者触发下一阶段逻辑。

2. 配置 TracingConfiguration

const tracingConfig: rcp.TracingConfiguration = {
  verbose: true,            // 打开详细跟踪
  infoToCollect: {
    incomingHeader: true,   // 收集传入 header 事件
    outgoingHeader: true,   // 收集传出 header 事件
    incomingData: true,     // 收集传入数据事件
    outgoingData: true      // 收集传出数据事件
  },
  collectTimeInfo: true,    // 采集时间信息(TimeInfo)
  httpEventsHandler: customHttpEventsHandler
};

const securityConfig: rcp.SecurityConfiguration = {
  tlsOptions: {
    tlsVersion: 'TlsV1.3'
  }
};

// 创建会话时挂上 tracing 配置
const session = rcp.createSession({
  requestConfiguration: {
    tracing: tracingConfig,
    security: securityConfig
  }
});

// 发起请求
session.get('http://developer.huawei.com').then((response) => {
  console.info(`Request succeeded, message is ${JSON.stringify(response)}`);
}).catch((err: BusinessError) => {
  console.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

几个关键开关:

  • verbose: true
    → 输出更详细的调试信息(配合 debugInfo 使用时尤其有用)。
  • infoToCollect
    • incomingHeader / outgoingHeader:谁在什么时候发/收了哪些 header;
    • incomingData / outgoingData:数据块的流动情况;
  • collectTimeInfo: true
    → 这一步是后面拿 精确时间点 的前提,response.timeInfo 才会有值。

三、TimeInfo:HTTP 请求全过程的“时间轴”

官方给的时间线可以简单理解为:

0 ms (请求开始)
  ↓ nameLookupTimeMs       // DNS 解析完成
  ↓ connectTimeMs          // 建连完成(TCP 完成)
  ↓ tlsHandshakeTimeMs     // TLS 握手完成
  ↓ preTransferTimeMs      // 业务请求数据发完
  ↓ startTransferTimeMs    // 收到首包响应数据
  ...
  ↓ totalTimeMs            // 整个请求结束

所有这些字段,都是“相对于 0 时刻”的耗时(单位一般是 ms)。

常见关注三大时间段

  1. 首包耗时:从请求发完到收到首包的时间
首包耗时 = startTransferTimeMs - preTransferTimeMs
  1. TLS 握手耗时(不包含建连)
TLS 耗时 = tlsHandshakeTimeMs - connectTimeMs
  1. 接收剩余数据的耗时
接收剩余数据耗时 = totalTimeMs - startTransferTimeMs
  • 对应问题:
    • DNS 慢?TLS 慢?服务端处理慢?还是下行带宽 / RTT 问题?
    • TimeInfo 就是拆开这些阶段的关键。

四、实战:打印首包 / TLS / 剩余数据耗时

这段示例就是专门帮你“算并打印三个关键指标”的:

import { rcp } from '@kit.RemoteCommunicationKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 1. 创建 session & URL
const session = rcp.createSession();
const requestURL = "https://www.example.com";

// 2. 配置:只关心时间信息的话,至少要打开 collectTimeInfo
const configuration: rcp.Configuration = {
  tracing: {
    collectTimeInfo: true
  }
};

// 3. 创建请求并挂上配置
const request = new rcp.Request(requestURL, "GET");
request.configuration = configuration;

// 4. 发起请求
session.fetch(request).then((response: rcp.Response) => {
  if (!response.timeInfo) {
    console.error(`timeInfo is undefined ${response.timeInfo}`);
    return;
  }

  const timeInfo = response.timeInfo;

  // 注意:字段可能为 undefined,做运算时要小心判空
  const remainderDataTime =
    (timeInfo.totalTimeMs ?? 0) - (timeInfo.startTransferTimeMs ?? 0);
  const firstPackageTime =
    (timeInfo.startTransferTimeMs ?? 0) - (timeInfo.preTransferTimeMs ?? 0);
  const TLSTime =
    (timeInfo.tlsHandshakeTimeMs ?? 0) - (timeInfo.connectTimeMs ?? 0);

  console.info(`首包耗时: ${firstPackageTime} ms`);
  console.info(`TLS 握手(不含建连)耗时: ${TLSTime} ms`);
  console.info(`接收剩余数据的耗时: ${remainderDataTime} ms`);
}).catch((err: BusinessError) => {
  console.error(`Response err, the err is ${JSON.stringify(err)}`);
});

你可以在此基础上做更多事情,比如:

  • 首包耗时 > 某个阈值 → 上报埋点,标记网络慢;
  • TLS 耗时过长 → 提示用户检查代理 / 中间网关;
  • 接收剩余耗时过长 → 有可能是服务端处理慢或下行带宽问题。

五、结合前面章节:TracingConfiguration 能怎么用?

给你几个后续可以串起来写博客 / 出考点的思路:

  1. 和 TransferConfiguration / PausePolicy 联动
    • 监控请求耗时,如果超过某阈值自动触发暂停 / 重试;
    • 通过 TimeInfo 定位到底是建连慢、TLS 慢、首包慢还是 body 很大。
  2. 和 Interceptor 拦截器联动
    • 在拦截器里统一打日志 + 打上 traceId;
    • TracingConfiguration 收集底层时间,拦截器收集“业务维度”信息,两者组合做完整链路追踪。
  3. 和 流式传输 配合
    • 使用 httpEventsHandler.onDataReceive + NetworkOutputQueue / downloadToStream:
      • 实时统计每块数据到达时间,做简单吞吐监控;
      • 或者对关键接口做实时“下载速度曲线”。
  4. 和 SecurityConfiguration 联动
    • 利用 TLS 时长(tlsHandshakeTimeMs)分析不同 TLS 版本、不同 CA 的握手影响;
    • 可以在测试环境切换配置,比较性能数据。

六、结尾小抄:TracingConfiguration 核心记忆点

  • TracingConfiguration 能配什么?
    • verbose:是否启用详细跟踪
    • infoToCollect:选择收集哪些事件(header / data 的 incoming / outgoing)
    • collectTimeInfo:是否采集 TimeInfo
    • httpEventsHandler:三大回调:
      • onHeaderReceive
      • onDataReceive
      • onDataEnd
  • TimeInfo 常用字段 & 计算公式:
    • firstPackageTime = startTransferTimeMs - preTransferTimeMs
    • TLSTime = tlsHandshakeTimeMs - connectTimeMs
    • remainderDataTime = totalTimeMs - startTransferTimeMs
  • 设备支持:
    • Phone / 2in1 / Tablet / Wearable
    • 5.1.1(19) 起:新增 TV
posted @ 2025-12-13 20:23  遇到困难睡大觉哈哈  阅读(3)  评论(0)    收藏  举报