簡析hotjar錄屏功能實現原理
眾所周知,hotjar中錄屏功能是其重要的一個賣點,看着很牛X酷炫的樣子,今天就簡單的分析一下其可能實現(這里只根據其請求加上個人理解分析,並不代表hotjar中真實實現必然如此)的原理。
1、獲取完整DOM內容
如果要實現完整的錄屏功能,在客戶端在沒有客戶允許的前提下,目前是無法做到的,所以只能考慮在服務端來實現,在服務端實現的第一步,就必然需要重現客戶端的渲染結果,此時需要完整的發送客戶端內容到服務端,在服務端進行完整的渲染。
從布瑪的效果來看,獲取DOM內容會涉及如下三個請求:
請求1 用來判斷該頁面內容在服務端是否存在
Request URL: https://in.hotjar.com/api/v1/sites/848493/pages/2338866123/content-id/34b2f50d09fbe08a4444e6691b1be779
Request Method: GET
Status Code: 200
//響應結果
{"exists": false}
請求2 預檢請求 沒啥說的,應該都知道干啥的
Request URL: https://in.hotjar.com/api/v1/sites/848493/url-hash/4f9e7b2f60ba35900e873ed12b1502ec/content
Request Method: OPTIONS
Status Code: 200
請求3 發送完整DOM內容
Request URL: https://in.hotjar.com/api/v1/sites/848493/url-hash/4f9e7b2f60ba35900e873ed12b1502ec/content
Request Method: POST
Status Code: 200
Request Payload
content: "{"docType":"<!DOCTYPE html>\n","rootId":1,"childre" .......
content_md5: "34b2f50d09fbe08a4444e6691b1be779"
page_id: 2338866123
page_url: "xxxxxxxxx.html"
//響應結果
{"page_content_id": 8784354270, "success": true}
從請求3 中可以看到,content部分其實就是對完整html的json化,這部分內容比較長,只貼出部分內容。
2、獲取鼠標移動軌跡
只是獲取完整DOM內容只是第一步,在hotjar的錄屏功能中,還有一個是獲取鼠標運動軌跡,想要繪制運動軌跡,必然要知悉鼠標在時間軸上的位置信息,所以hotjar中,必然要采集鼠標在不同時間點的位置信息,這個可以通過其websocket 請求
Request URL: wss://ws7.hotjar.com/api/v1/client/ws
Request Method: GET
Status Code: 101 Switching Protocols
在ws 請求過程中,會有mouse-move數據包的發送,其基本結構如下:
mouse_move: [{time: 106597, x: 215, y: 115}, {time: 106695, x: 181, y: 105}, {time: 106796, x: 134, y: 139},…]
page_visit_id: 14777325238
page_visit_key: "e9fa998e-5811-4d2f-81d2-bd296c7129af"
其中可以看到mouse_move 數據結構中,包含了時間軸上不斷變化的坐標值(x,y),有了基於時間軸的xy坐標,我們繪制內容就變的不那么復雜了。
3、檢測並發送DOM變化
除了鼠標運行軌跡之外,用戶在頁面上的所有行為都會被完整的記錄下來,頁面的任何變化也都被記錄了下來,如果需要在服務端完整的重新演化這種變化,那么需要把完整的變化結構發送到服務器,讓服務端進行變化回溯,hotjar是通過ws中發送mutation發送這種結構包的,當然要發送這種結構包,首先要先觀測DOM變化,這里也有一種簡單的方式(暫時不確定hotjar的實現)HTML5 DOM4級MutatioObserver方法,可以檢查頁面中的DOM是否發生變化,大家可以做一下簡單的測試:
//選擇目標觀測節點
let target = document.querySelector('目標節點選擇器');
// 創建觀察者對象
var observer = new window.MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
});
// 觀測項配置:
var config = { attributes: true, childList: true }
// 開始觀測目標節點
observer.observe(target, config);
獲取到變化的DOM結構(這種變化也是時序的變化,因為任何操作都可能導致變化,變化必然是有先后順序的),然后通過ws發送到服務器,通過chrome network可以看到ws中mutation基本的包結構如下:
mouse_move: [{time: 118994, x: 404, y: 135}]
mutation: [{time: 118308,…}, {time: 118312,…}, {time: 118336, c: [{id: 7480,…}]}
page_visit_id: 14777325238
page_visit_key: "e9fa998e-5811-4d2f-81d2-bd296c7129af"
里面包含了DOM節點變化,其中包含變化節點如何變化的(通過節點的所有attribute來應用)
4、變化和軌跡回溯生成視頻
最后一切數據准備完畢,需要生成視頻了,生成視頻當然涉及很多的計算,因為要演化和回溯用戶的所有操作,我猜可能的思路是這樣的:
- 在服務器啟動瀏覽器 並 啟動錄屏軟件(錄屏軟件只是猜測可能有其它多種方式)
- 根據頁面發送的完整DOM進行初始化內容展示
- 按照時序合並鼠標軌跡和mutation包數據
- 根據時間軸自動操作改變DOM
- 訪次結束完成錄制
總結
hotjar中還涉及到更多的細節實現,里面很多內容也並沒有考慮,比如發送view_port report_content包等都沒什么在文章中體現出來,但這些並不影響主線分析,另外因為只是簡要分析,所以並不涉及實現細節,有興趣的歡迎留言討論。
