行为监控-系列小解读

111 阅读2分钟

userAgent

我们在行为监控中,请求头字段userAgent 其实有很多信息,需要获取上报,但是直接手动处理较为繁琐,因此通通过这个 'ua-parser-js';

  // 获取用户设备相关信息
  getUserAgent = (useragent) => {
    const parserData = parser(useragent);
    const browserName = parserData.browser.name; // 浏览器名
    const browserVersion = parserData.browser.version; // 浏览器版本号
    const osName = parserData.os.name; // 操作系统名
    const osVersion = parserData.os.version // 操作系统版本号
    const deviceType = parserData.device.type; // 设备类型
    const deviceVendor = parserData.device.vendor || ''; // 设备所属公司
    const deviceModel = parserData.device.model || ''; // 设备型号
    const engineName = parserData.engine.name; // engine名
    const engineVersion = parserData.engine.version; // engine版本号
    return {
      browserName,
      browserVersion,
      osName,
      osVersion,
      deviceType,
      deviceVendor,
      deviceModel,
      engineName,
      engineVersion,
    };

  }

用户行为记录栈

一些用户行为分析,以及错误排查的时候,是需要将关键行为,按照顺序存储上报,

  BreadStack = ()=>{
  
  class Stack {

      // 这里用constructor 貌似不是很好
      //为什么要用静态的
      private maxBread: number;
      private stack: any[];

    push = (item) => {
      if (this.stack.length >= this.maxBread) {
        this.stack.shift()
      }
      this.stack.push(item)
    }

    pop = () => {
      return this.stack.pop()
    }

    getStack = () => {
      return this.stack.length
    }
    // 这种清除方法真的好吗
    clear = () => {
      this.stack = []
    }
  }

  }

}

路由信息监听

  1. 一般主要针对于spad 单页面应用来进行 监听。
  // 重写pushState 和 replaceState 因为监听不到
  wrHistory = (type) => {
    let origin = window.history[type]
    if (type === 'pushState') {
      let event = new Event('pushState')
      window.dispatchEvent(event)
    }
    if (type === 'replaceState') {
      let event = new Event('replaceState')
      window.dispatchEvent(event)
    }
    return origin.apply(this, type)
  }

  rewriteHistory = () => {
    window.history.pushState = this.wrHistory('pushState')
    window.history.replaceState = this.wrHistory('replaceState')
  }

  // 监听路由变化

  watchHashRouteChange = (handle: Function) => {
    window.addEventListener('hashchange', () => {
      handle()
    })

  }

  watchHistoryRouteChange = (handle: Function) => {
    window.addEventListener('popstate', () => {
      handle()
    })
  }

  initRouter = () => {

    const handle = () => {
      const metrics = {
        type: 'router',
        url: window.location.href,
        time: new Date().getTime(),
      }

      this.metrics.set(metricsName.RCR, metrics)
      // 记录到行为记录追踪
      const behavior = {
        category: metricsName.RCR,
        data: metrics,
        ...this.getExtends(),
      } as behaviorStack;
      this.breadcrumbs.push(behavior);
    }

    this.watchHashRouteChange(handle)
    this.watchHashRouteChange(handle)




  }


pv,uv

  • PV 是页面访问量
  • UV 是24小时内(00:00-24:00)访问的独立用户数。

pv 再用户访问当前路由页面进行记录,uv 后端配合ip 及登录信息判断是否为首次登陆

  initPv = () => {
    const handler = () => { 
      const metrices = {
        origin: window.location.origin,
        pathname: window.location.pathname,
        time: new Date().getTime(),
        originInfo: this.getOriginInfo()
      } 
      this.userSendHandler(metrices)
     }
     // 页面加载完毕后进行上报
    afterLoad(() => {
      handler()
    })
  }

如何上报呢

一般来将,常见方式,一个是用XHR 以及fetch 请求上报,img标签,以及H5里得sendBeacon 来,但是我当时业务上实际采用得 sendBeacon 加降级ajax 上报处理。

xhr 方式,兼容性更好,但是可能阻塞页面加载,以及特殊场景无法覆盖,关闭 sendbeaco 非阻塞式,但是兼容性差 img,虽然支持跨越,但是由于是get请求,资源存入url ,不同浏览器对于url 地址请求可能会被截断,长度会有要求。