用戶行爲錄幀調研

關鍵點

  • 首先,每一次會話都有一個惟一的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。複製代碼
相關文章
相關標籤/搜索