API监控
简介
SDK 通过重写浏览器原生 fetch 与 XMLHttpRequest 对象,在渲染进程内实现对所有网络请求的透明监控。
无论业务代码使用 fetch、axios 还是其他基于 XHR 的库,都会被无感知地拦截并上报性能与错误数据。
渲染进程API监控原理
1. 重写 fetch
SDK 在初始化阶段调用 hackFetch,将全局 fetch 替换为自定义实现:
请求阶段
在真正发起请求前,SDK 会:- 记录请求开始时间戳
- 保存请求参数、URL、方法、自定义请求头
响应阶段
请求完成后(无论成功或失败),SDK 会:- 计算耗时
- 读取响应状态码、响应头、响应体
- 根据
Content-Type判断是 API 还是 静态资源 - 若开启
apiDetail,则收集请求体与响应体(可自定义过滤函数) - 若状态码 ≥ 400 或
retcode非 0,则标记为错误并上报
异常阶段
网络错误、跨域、超时、手动abort等异常同样会被捕获,并补充错误类型与堆栈。
2. 重写 XMLHttpRequest
对于仍使用 XHR 的代码,SDK 通过 hackXHR 以类似逻辑进行拦截:
- 监听
readystatechange、loadend、error、timeout、abort事件 - 在
send时记录时间戳,并在loadend时统一计算耗时 - 支持 SSE(Server-Sent Events)持续上报
- 支持配置是否上报
abort请求 - 支持自定义
urlHandler、reqParamHandler、resBodyHandler等钩子,灵活控制上报内容
3. 上报内容
| 字段 | 说明 |
|---|---|
url | 请求地址(可自定义格式化) |
status | HTTP 状态码 |
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
- api接口请求是否正确是根据isErr判断来的,因此retCodeHandler的设置非常重要
- 返回的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 通过 hackHttp 和 hackNet 两个钩子,分别拦截 Node.js 原生 http/https 模块和 Electron 的 net 模块发起的请求,监控逻辑和上报内容与渲染进程基本一致,但仅作用于主进程内部发起的网络请求。
| 钩子 | 拦截对象 | 适用场景 |
|---|---|---|
| hackHttp | require('http') / require('https') | 传统 Node.js 网络请求 |
| hackNet | require('electron').net | Electron 专用网络栈 |
⚠️ 注意:这两个钩子只能监控主进程自身发起的请求,无法捕获渲染进程(BrowserWindow、WebContents)内部的
fetch或XMLHttpRequest。
配置方式与渲染进程相同,可复用上一节的 api 配置。
caution
主进程API监控目前没有做异常捕获上报逻辑,在后续版本中会陆续添加这部分功能