Skip to main content

API监控

简介

SDK 通过重写浏览器原生 fetchXMLHttpRequest 对象,在渲染进程内实现对所有网络请求的透明监控。
无论业务代码使用 fetchaxios 还是其他基于 XHR 的库,都会被无感知地拦截并上报性能与错误数据。

渲染进程API监控原理

1. 重写 fetch

SDK 在初始化阶段调用 hackFetch,将全局 fetch 替换为自定义实现:

  • 请求阶段
    在真正发起请求前,SDK 会:

    • 记录请求开始时间戳
    • 保存请求参数、URL、方法、自定义请求头
  • 响应阶段
    请求完成后(无论成功或失败),SDK 会:

    • 计算耗时
    • 读取响应状态码、响应头、响应体
    • 根据 Content-Type 判断是 API 还是 静态资源
    • 若开启 apiDetail,则收集请求体与响应体(可自定义过滤函数)
    • 若状态码 ≥ 400 或 retcode 非 0,则标记为错误并上报
  • 异常阶段
    网络错误、跨域、超时、手动 abort 等异常同样会被捕获,并补充错误类型与堆栈。

2. 重写 XMLHttpRequest

对于仍使用 XHR 的代码,SDK 通过 hackXHR 以类似逻辑进行拦截:

  • 监听 readystatechangeloadenderrortimeoutabort 事件
  • send 时记录时间戳,并在 loadend 时统一计算耗时
  • 支持 SSE(Server-Sent Events)持续上报
  • 支持配置是否上报 abort 请求
  • 支持自定义 urlHandlerreqParamHandlerresBodyHandler 等钩子,灵活控制上报内容

3. 上报内容

字段说明
url请求地址(可自定义格式化)
statusHTTP 状态码
method请求方法
duration耗时(ms)
ret业务返回码(取自 retcode / code / ret / errcode
isErr是否为业务错误
param请求参数(可选)
data响应体(可选)
reqHeaders / resHeaders指定头信息(可选)
trace / span链路追踪 ID(可选)
nextHopProtocol协议类型(h2 / http/1.1 等)

4. 配置示例

new Aegis({
id: 'your-id',
reportApiSpeed: true,
api: {
apiDetail: true, // 上报请求/响应详情
reportAbort: false, // 上报 abort 请求
reqHeaders: ['x-token'], // 指定要上报的请求头
resHeaders: ['content-type'],
retCodeHandler: (data, url) => ({
isErr: data.code !== 0,
code: data.code.toString(),
}),
urlHandler: (url, body) => url.split('?')[0], // 去掉 query
},
});

4.1 retCodeHandler

retCodeHandler,假如后台返回数据为:

{
body: {
code: '200',
retCode: '0',
data: {
// xxx
}
}
}

业务需要:code不为'200',或者retCode不为'0',此次请求就是错误的。此时只需进行以下配置:

new Aegis({
// xxx
api: {
retCodeHandler(data) {
// 注意如果这里拿到的data是string类型,需要对象的话,要手动parse下
try {
data = JSON.parse(data)
} catch(e) {}
return {
isErr: data.body.code !== '200' || data.body.retCode !== '0',
code: data.body.code
}
}
}
})
danger
  1. api接口请求是否正确是根据isErr判断来的,因此retCodeHandler的设置非常重要
  2. 返回的code需要是string类型,否则会上报失败

4.2 自定义过滤函数

apiDetail: true 时,SDK 会默认把完整的请求体完整的响应体上报。
如果其中包含敏感字段(如密码、token、手机号等),你可以通过以下两个钩子进行脱敏或裁剪:

钩子触发时机参数返回值
reqParamHandler上报前处理请求体(body, url)处理后的字符串
resBodyHandler上报前处理响应体(body, url, ctx)处理后的字符串
4.2.1 示例:脱敏手机号
new Aegis({
id: 'your-id',
reportApiSpeed: true,
api: {
apiDetail: true,
// 1. 请求体脱敏
reqParamHandler: (body, url) => {
if (typeof body !== 'string') body = JSON.stringify(body);
// 把手机号中间四位替换成 ****
return body.replace(/"phone":"(\d{3})\d{4}(\d{4})"/g, '"phone":"$1****$2"');
},
// 2. 响应体脱敏
resBodyHandler: (body, url, ctx) => {
try {
const data = JSON.parse(body);
// 删除敏感字段
delete data.token;
delete data.secret;
return JSON.stringify(data);
} catch {
return body; // 解析失败原样返回
}
},
},
});
4.2.2 示例:只保留关键字段
api: {
apiDetail: true,
reqParamHandler: (body, url) => {
if (url.includes('/login')) {
// 登录接口只保留用户名
const { username } = JSON.parse(body);
return JSON.stringify({ username });
}
return body;
},
resBodyHandler: (body, url) => {
if (url.includes('/user/info')) {
// 用户信息接口只保留 id 和 name
const { id, name } = JSON.parse(body);
return JSON.stringify({ id, name });
}
return body;
},
}

5. 注意事项

  • 仅对渲染进程生效;主进程请使用主进程 SDK。
  • API监控配置详见配置说明-插件配置-API配置表

主进程API监控原理

1. 主进程 API 监控

主进程 SDK 通过 hackHttphackNet 两个钩子,分别拦截 Node.js 原生 http/https 模块和 Electron 的 net 模块发起的请求,监控逻辑和上报内容与渲染进程基本一致,但仅作用于主进程内部发起的网络请求。

钩子拦截对象适用场景
hackHttprequire('http') / require('https')传统 Node.js 网络请求
hackNetrequire('electron').netElectron 专用网络栈

⚠️ 注意:这两个钩子只能监控主进程自身发起的请求,无法捕获渲染进程(BrowserWindow、WebContents)内部的 fetchXMLHttpRequest

配置方式与渲染进程相同,可复用上一节的 api 配置。

caution

主进程API监控目前没有做异常捕获上报逻辑,在后续版本中会陆续添加这部分功能