JS实现微信小程序数据埋点与异常监控原理

作者:工具松鼠时间:2026-10-22 15:27:37浏览:218

本文详解如何在微信小程序中通过劫持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实现微信小程序监控原理的介绍,希望有所帮助。如有疑问请留言,小编会及时回复。感谢支持!

作者最新文章