2

background

In the past, the company used GrowingIo Web JS SDK provided by it in each project, but recently, due to the expiration of the use period and some other considerations, it is going to use Shence for data burying and data analysis, so it needs to be moved. GrowingIo Web JS SDK introduced in each project, and then Web JS SDK provided by Sensors.

plan

If you still use the independent introduction of Web JS SDK in each project, you need to first sort out that there are multiple projects with buried point requirements, and then arrange to notify the front-end students of each business group to introduce them in the iterative development. Do you find it particularly troublesome, it is obviously the same Web JS SDK but needs to be introduced multiple times, and it also involves cross-group collaboration, task allocation, resource arrangement and other issues. What's more, if another buried tool is used next time, the repetitive things will be done again, which is thankless.

Therefore, we hope that after it can be introduced somewhere, the project does not need to be introduced independently. Do you think this solution is very similar to the ideas of gateway services, middleware, and interceptors? Can we use this kind of thinking to solve it? The answer is yes, static routing service requests to the front of html script injection Shence Web JS SDK

路由服务引入神策.png

For some front-end and back-end separation projects ( Vue、React html script can be operated in the front-end routing service and injected into Web JS SDK , but for some projects that are not separated from the front-end and back-end (such as the freemarker project) how to deal with it? Can unified processing be done on the webagent In fact, it is also feasible. The interceptor can intercept the response of the response header Content-Type: text/html , and the operation html injected into the Web JS SDK ; if it is not this response type, it will not be processed. But in practice, in view of the fact that there are few projects that are not separated from the front and back ends, we still adopt the first solution, which is introduced in the project independently.

Encapsulation God Web JS SDK

SDK provides the function of full buried point, which is desired to be enabled in the project, so it needs to be repackaged and initialized 061ed0b0fa7651, you can refer to the following package:

;(function () {
  /** 判断环境 */
  var hostname = window.location.hostname;
  var serverUrl = 'https://xxx?project=default'; // 测试环境数据接收地址
  if (hostname === 'www.cassmall.com' || hostname === 'h.cassmall.com') {
    serverUrl = 'https://xxx?project=production'; // 生产环境数据接收地址
  }
  // 开启全埋点,Web JS SDK 全埋点包括三种事件:Web 页面浏览、Web 元素点击、Web 视区停留
  function addShenCeScript() {
    window.cassSensors = window['sensorsDataAnalytic201505'];
        // 初始化 SDK
    window.cassSensors.init({
      server_url: serverUrl, // 数据接收地址
      is_track_single_page: true, // 单页面配置,默认开启,若页面中有锚点设计,需要将该配置删除,否则触发锚点会多触发 $pageview 事件
      heatmap: {
                /**
                * Web 元素点击($WebClick)
                * 是否开启点击图,default 表示开启,自动采集 $WebClick 事件,可以设置 'not_collect' 表示关闭。
                * 默认只有点击 a input button textarea 四种元素时,才会触发 $WebClick 元素点击事件
                */
        clickmap: 'default',
                /**
                * 视区停留事件($WebStay)
                * 是否开启触达图,default 表示开启,自动采集 $WebStay 事件,可以设置 'not_collect' 表示关闭。
                * 需要 Web JS SDK 版本号大于 1.9.1
                */
        scroll_notice_map: 'default',
                // 通过 collect_tags 配置是否开启其他任意元素的全埋点采集(默认不采集),其中 div 通过配置最多可以采集 3 层嵌套情况。
        collect_tags: { 
          div: {
            max_level: 3, // 默认是 1,即只支持叶子 div。可配置范围是 [1, 2, 3],非该范围配置值,会被当作 1 处理。
          },
          li: true,
          span: true,
          i: true,
          img: true
        },
      },
    })
        // 注册公共属性
    window.cassSensors.registerPage({
      platform_type: 'web',
      path_name: window.location.pathname,
    })
        /**
        * Web 页面浏览($pageview)
        * 设置之后,SDK 就会自动收集页面浏览事件,以及设置初始来源。
        */
    window.cassSensors.quick('autoTrack');

        /** 获取用户登录ID,用户登录后,开发人员调用login,将用户登录ID传给SDK,后续该设备上所有事件的distinct_id就会变成用户所对应的登录ID。*/
    ajax({
      url: '/webim/user/jwt_token',
      type: 'GET',
      success: function (res) {
        try {
          var data = JSON.parse(res);
          window.cassSensors.login(data.username);
        } catch (e) { }
      },
      error: function (error) { }
    });
  }

  var script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');

  var explorer = window.navigator.userAgent;
  if (explorer.indexOf('MSIE') >= 0) {
    // ie
    script.onreadystatechange = function () {
      if (this.readyState === 'loaded' || this.readyState === 'complete') {
        addShenCeScript();
      }
    }
  } else {
    // chrome
    script.onload = function () {
      addShenCeScript();
    }
  }
  script.setAttribute(
    'src',
    'https://mstatic.cassmall.com/assets/sensors/sensorsdata1.19.4.min.js'
  );
    
    /** 封装ajax请求 */
  function ajax(params) {
    params = params || {};
    params.data = params.data || {};
    // 判断是ajax请求还是jsonp请求
    var json = params.jsonp ? jsonp(params) : json(params);
    // ajax请求 
    function json(params) {
      // 请求方式,默认是GET
      params.type = (params.type || 'GET').toUpperCase();
      // 避免有特殊字符,必须格式化传输数据
      params.data = formatParams(params.data);
      var xhr = null;

      // 实例化XMLHttpRequest对象 
      if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
      } else {
        // IE6及其以下版本 
        xhr = new ActiveXObjcet('Microsoft.XMLHTTP');
      };

      // 监听事件,只要 readyState 的值变化,就会调用 readystatechange 事件
      xhr.onreadystatechange = function () {
        // readyState属性表示请求/响应过程的当前活动阶段,4为完成,已经接收到全部响应数据
        if (xhr.readyState == 4) {
          var status = xhr.status;
          // status:响应的HTTP状态码,以2开头的都是成功
          if (status >= 200 && status < 300) {
            var response = '';
            // 判断接受数据的内容类型
            var type = xhr.getResponseHeader('Content-type');
            if (type.indexOf('xml') !== -1 && xhr.responseXML) {
              response = xhr.responseXML; //Document对象响应 
            } else if (type === 'application/json') {
              response = JSON.parse(xhr.responseText); //JSON响应 
            } else {
              response = xhr.responseText; //字符串响应 
            };
            // 成功回调函数
            params.success && params.success(response);
          } else {
            params.error && params.error(status);
          }
        };
      };

      // 连接和传输数据 
      if (params.type == 'GET') {
        // 三个参数:请求方式、请求地址(get方式时,传输数据是加在地址后的)、是否异步请求(同步请求的情况极少);
        xhr.open(params.type, params.url + '?' + params.data, true);
        xhr.send(null);
      } else {
        xhr.open(params.type, params.url, true);
        //必须,设置提交时的内容类型 
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
        // 传输数据
        xhr.send(params.data);
      }
    }

    //格式化参数 
    function formatParams(data) {
      var arr = [];
      for (var name in data) {
        // encodeURIComponent() :用于对 URI 中的某一部分进行编码
        arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
      };
      // 添加一个随机数参数,防止CDN缓存 
      arr.push('v=' + random());
      return arr.join('&');
    }

    // 获取随机数 
    function random() {
      return Math.floor(Math.random() * 10000 + 500);
    }
  }
  if (!window.cassSensors) {
    document.getElementsByTagName('head')[0].appendChild(script);
  }
})()

记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。