微信小程序JS实现监控

作者: a333661d6d6e | 来源:发表于2018-10-08 19:49 被阅读62次

    浏览器web端的SDK数据埋点上报,其实原理大同小异:通过劫持原始方法,获取需要上报的数据,最后再执行原始方法,这样就能实现无痕埋点。



    我们在开发的时候,发送ajax一般用的都是封装好的库,例如jQuery,Axios等,然而这些库,底层仍然用的是浏览器原生的XMLHttpRequest对象,因此,我们只需要修改XMLHttpRequest对象即可。

    // 把这段代码放在所有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

    小程序的运行环境并没有window和document对象,它只暴露了一个wx全局对象,发送网络请求则是通过wx.request这个api,因此,这次我们需要拦截的就是wx.request方法

    我们更改一下wx.request

    wx.request = function() {
     console.log('前端攻城小牛QQ群:864305860');
    }
    

    这时控制台会报错TypeError: Cannot set property request of #<Object> which has only a getter

    这是因为,wx.request这个属性,只有get方法而没有set方法,我们可以通过Object.getOwnPropertyDescriptor验证:

    const des = Object.getOwnPropertyDescriptor(wx, 'request');
    // des {
    // configurable: true,
    // enumerable: true,
    // get: f(),
    // set: undefined
    // }
    

    我们可以换种方式修改:

    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请求,也会被我们认为是普通的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之前,保留一份最原始的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();
    

    本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
    对web开发技术感兴趣的同学,欢迎加入Q群:864305860,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
    最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

    相关文章

      网友评论

      本文标题:微信小程序JS实现监控

      本文链接:https://www.haomeiwen.com/subject/epgjaftx.html