JS实现微信小程序数据埋点与异常监控原理
本文详解如何在微信小程序中通过劫持wx.request实现无痕数据埋点,解决属性只读限制,并探讨防止上报死循环的两种方案。同时介绍利用App全局onError进行异常监控的方法及注意事项,为小程序SDK开发提供完整原理参考。
Web端Ajax监控原理
原理
此前在浏览器Web端进行SDK数据埋点上报时,核心逻辑与小程序场景相似:通过劫持原生方法获取目标数据,随后执行原始方法,从而实现无痕埋点。
以监控Web页面Ajax请求为例,目标是在每次发送Ajax时,于控制台打印出请求的URL。
开发中通常使用jQuery、Axios等封装库,但其底层仍依赖浏览器原生的XMLHttpRequest对象。因此,只需修改XMLHttpRequest对象即可实现监控。
需注意,虽然JavaScript灵活性高,修改原生方法容易,但此举并不被推荐。
// 把这段代码放在所有JS代码之前,我们就实现了拦截ajax的需求
window.XMLHttpRequest.prototype.open = (function(originOpen) {
return function(method, url, async) {
console.log('发送了ajax,url是: ', url);
return originOpen.apply(this, arguments);
};
})(window.XMLHttpRequest.prototype.open);
在立即执行函数中,将原生open方法暂存为originOpen,外层包裹新函数以打印URL,最后通过originOpen.apply执行原生方法,从而完成无痕拦截。
小程序wx.request拦截实现
监控小程序
拦截wx.request
小程序环境无window和document对象,仅暴露wx全局对象。网络请求通过wx.request API发起,故需拦截该方法。
尝试直接修改wx.request。
wx.request = function() {
console.log('66666');
}
控制台报错TypeError: Cannot set property request of #<Object> which has only a getter,表明该属性仅有getter而无setter。
可通过Object.getOwnPropertyDescriptor验证wx.request属性描述符。
const des = Object.getOwnPropertyDescriptor(wx, 'request');
// des {
// configurable: true,
// enumerable: true,
// get: f(),
// set: undefined
// }
采用其他方式修改wx.request。
const originRequest = wx.request;
Object.defineProperty(wx, 'request', {
configurable: true,
enumerable: true,
writable: true,
value: function() {
const config = arguments[0] || {};
const url = config.url;
console.log('发送了ajax,url是: ', url);
return originRequest.apply(this, arguments);
}
});
至此实现拦截功能。
小程序异常监控与上报防死循环
监控异常
小程序注册函数App提供全局onError方法,可在入口文件app.js中预先注册该方法。
App({ onError: function(err) {
console.log('上报错误啦!');
wx.request({
url: 'http://monitor.com/monitor/error',
data: err
})
}
})
App({
// 其他逻辑
})
需注意,若后续代码重写onError,将导致之前注册的onError失效。
解决方法:监控SDK可暴露接口,由接入方在onError中调用该接口。
App({
onError: function (err) {
monitor.notifyError(err)
}
})
上报数据
收集数据后需上报后台,通常仍使用wx.request发送请求。
此处易出现死循环:若使用被包装过的wx.request上报,上报请求本身会被视为普通Ajax触发上报,导致无限循环发送。
解决方法包括:
方案1
包装wx.request时判断URL,若为上报接口则直接调用原始方法,不再触发上报逻辑。
const originRequest = wx.request;
Object.defineProperty(wx, 'request', {
configurable: true,
enumerable: true,
writable: true,
value: function() {
const config = arguments[0] || {};
const url = config.url;
if (url.indexOf('http://monitor.com') > -1) {
// 直接发送请求,不上报
return originRequest.apply(this, arguments);
}
console.log('上报ajax数据啦!');
wx.request({
url: 'http://monitor.com/monitor/ajax',
data: config.data
})
return originRequest.apply(this, arguments);
}
});
方案2
包装前保留最原始wx.request方法,所有上报请求直接调用原始方法,绕过包装逻辑。
const myRequest = wx.request;
const wrapRequest = function () {
const originRequest = wx.request;
Object.defineProperty(wx, 'request', {
configurable: true,
enumerable: true,
writable: true,
value: function() {
const config = arguments[0] || {};
const url = config.url;
console.log('上报数据啦!');
// 使用最原始的request方法
myRequest({
url: 'http://monitor.com/monitor/ajax',
data: config.data
})
return originRequest.apply(this, arguments);
}
});
}
wrapRequest();
其他事项
实际开发涉及项目鉴权、SDK代码结构、上报前数据收集与聚合等细节,本文不展开。
总结
以上为JS实现微信小程序监控原理的介绍,希望有所帮助。如有疑问请留言,小编会及时回复。感谢支持!
JS表单序列化出现中文乱码怎么解决
2026-11-05 17:21:05
JS代码在线格式化工具推荐:无需安装快速美化
2026-11-05 17:17:49
WebStorm内置JS代码格式化功能怎么用
2026-11-05 10:10:47
在线JS代码格式化与混淆压缩工具推荐及使用指南
2026-11-03 20:31:53
CodePen、JSFiddle与RunJS对比:哪款在线JavaScript编辑器更好用
2026-11-03 18:52:45
