用户行为录帧调研

关键点

  • 首先,每一次会话都有一个惟一的session ID,这是串联起全部行为的纽带。
  • 其次,用户行为又分红两个部分,其一是用户的操做,好比鼠标滑动,点击,页面滚动等,其二是页面的变化。这二者咱们都统称为用户行为,记录在同一个队列中。
  • 一开始的时候,系统会记录下初始的页面做为第一帧,这是惟一的一次完整页面记录。
  • 针对用户操做,咱们会记录事件的类型,鼠标位置等关键信息,保存到队列中。
  • 针对页面变更,咱们会起一个mutationObserve侦听页面的改动,每次只记录改动的部分,保存到队列中。
  • 不管是事件仍是页面改动,都是对等的一帧,每一帧都会有当前时间,与上一帧间隔时间等基本信息用户还原
  • 一旦出错,SDK就把队列发送到监控系统,并清空当前队列。
  • 还原端根据记录的行为队列,根据时间逐一播放出来。最终造成一个相似于视频的效果。

初步思路css

方式一:html

  1. 前端收集信息,首先,初始化的时候记录一个页面的初始状态,而后利用 MutationObserver 监听dom的改变事件,而后监听全部的鼠标事件、滚动事件等等全部的页面变化。
  2. 在合理的时机把这些信息队列上传到服务器,如页面出错时等。
  3. 后台分析前端收集到的信息,转为图片,而后造成"视频",或者用户行为栈。提供对应的调用 api。
  4. 前端须要查找问题时,根据用户id等信息找到对应的出错栈。

方式二:前端

  1. 前端根据 html 转为对应的图片(能够转为 base64 格式)
  2. 将图片发送给后台
  3. 后台将图片按序组成"视频"

现有SDKnode

  1. fundebug

录屏(截图)

  1. html2canvas
  2. puppeteer
  3. rrweb+rrweb-player+rrweb-snapshot

html2canvas介绍

html2canvas 是经过分析页面中已加载好的 DOM 元素,而后 canvas 将生成的 DOM 节点绘制在画布上,最后转换为图片。它不是真正的截屏,只是根据页面元素信息还原出图片,因此并非 100% 和页面相同的。git

局限性github

  • 页面中的图片不能跨域
  • 不是全部的 css 特性都支持,如不支持 box-shadow、filter 等
  • 不支持截取插件内容,如 Flash
  • 不支持 iframe 内容

浏览器支持web

  • Firefox 3.5+
  • Google Chrome
  • Opera 12+
  • IE9+
  • Edge
  • Safari 6+

puppeteer介绍

Puppeteer 是 Google Chrome 团队官方的无界面(Headless)Chrome 工具,它是一个 Node 库,提供了一个高级的 API 来控制 DevTools协议上的无头版 Chrome 。canvas

局限性api

  • Puppeteer 须要 Chromium。其主要应用在自动化测试上。

功能跨域

  • 生成页面的截图和PDF。
  • 抓取SPA并生成预先呈现的内容(即"SSR")。
  • 从网站抓取你须要的内容。
  • 自动表单提交,UI测试,键盘输入等
  • 建立一个最新的自动化测试环境。使用最新的JavaScript和浏览器功能,直接在最新版本的Chrome中运行测试。
  • 捕获您的网站的时间线跟踪,以帮助诊断性能问题。

结论 html2canvas 更适合于 C 端的用户行为截图跟踪,而 Puppeteer 适用于自动化测试。

rrweb介绍

rrweb 主要由 3 部分组成:

  1. rrweb-snapshot,包含 snapshot 和 rebuild 两个功能。snapshot 用于将 DOM 及其状态转化为可序列化的数据结构并添加惟一标识;rebuild 则是将 snapshot 记录的数据结构重建为对应的 DOM。
  2. rrweb,包含 record 和 replay 两个功能。record 用于记录 DOM 中的全部变动(mutation);replay 则是将记录的变动按照对应的时间一一重放。
  3. rrweb-player,为 rrweb 提供一套 UI 控件,提供基于 GUI 的暂停、快进、拖拽至任意时间点播放等功能。

rrweb适用场景:

  • 用户行为分析;
  • 远程debug;
  • 录制操做;
  • 实时协做;

局限性

  • 社区资源较少
  • 部分代码用较旧的模式写的,有未知坑

最终结论

综合来看,结合思路一,基于 rrweb 来开发是最可行最快捷的。

Demo

目前,我基于 rrweb 已经作了个 demo 出来。如下是初步成果: demo代码

补充资料

rrweb的一些思路原理

zhuanlan.zhihu.com/p/60639266

MutationObserver介绍

Mutation Observer API 用来监视 DOM 变更。DOM 的任何变更,好比节点的增减、属性的变更、文本内容的变更,这个 API 均可以获得通知。

特色

  • 它等待全部脚本任务完成后,才会运行(即异步触发方式)。
  • 它把 DOM 变更记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变更。
  • 它既能够观察 DOM 的全部类型变更,也能够指定只观察某一类变更。

example // Select the node that will be observed for mutations var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList, observer) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();
复制代码

observe方法接受两个参数,第一个是所要观察的DOM元素是article,第二个是所要观察的变更类型(子节点变更和属性变更),方法调用时必须指定一种或多种变更类型,不然报错,变更类型以下:

boolean childList = false;
boolean attributes;
boolean characterData;
boolean subtree = false; //表示是否将该观察器应用于该节点的全部后代节点。
boolean attributeOldValue; //表示观察attributes变更时,是否须要记录变更前的属性值。
boolean characterDataOldValue; //表示观察characterData变更时,是否须要记录变更前的值。
sequence<DOMString> attributeFilter;//数组,表示须要观察的特定属性(好比['class','src'])
复制代码

disconnect方法用来中止观察。调用该方法后,DOM 再发生变更,也不会触发观察器。 takeRecords方法用来清除变更记录,即再也不处理未处理的变更。该方法返回变更记录的数组。

MutationRecord对象

DOM 每次发生变化,就会生成一条变更记录(MutationRecord 实例)。该实例包含了与变更相关的全部信息。Mutation Observer 处理的就是一个个MutationRecord实例所组成的数组。 MutationRecord对象包含了DOM的相关信息,有以下属性:

type:观察的变更类型(attribute、characterData或者childList)。
target:发生变更的DOM节点。
addedNodes:新增的DOM节点。
removedNodes:删除的DOM节点。
previousSibling:前一个同级节点,若是没有则返回null。
nextSibling:下一个同级节点,若是没有则返回null。
attributeName:发生变更的属性。若是设置了attributeFilter,则只返回预先指定的属性。
oldValue:变更前的值。这个属性只对attribute和characterData变更有效,若是发生childList变更,则返回null。复制代码
相关文章
相关标签/搜索