日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
讓前端監(jiān)控數(shù)據(jù)采集更高效

 隨著業(yè)務(wù)的快速發(fā)展,我們對生產(chǎn)環(huán)境下的問題感知能力越來越關(guān)注。作為距離用戶最近的一層,前端的表現(xiàn)是否可靠、穩(wěn)定、好用,很大程度上決定著用戶對整個產(chǎn)品的體驗和感受。因此,對于前端的監(jiān)控不容忽視。

為大足等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及大足網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、大足網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

搭建一套前端監(jiān)控平臺需要考慮的方面很多,比如數(shù)據(jù)采集、埋點模式、數(shù)據(jù)處理和分析、報警以及監(jiān)控平臺在具體業(yè)務(wù)中的應(yīng)用等等。在這所有環(huán)節(jié)中,準(zhǔn)確、完整、全面的數(shù)據(jù)采集是一切的前提,也為后續(xù)的用戶精細(xì)化運營提供基礎(chǔ)。

前端技術(shù)的日新月異給數(shù)據(jù)采集也帶來了變化和挑戰(zhàn),傳統(tǒng)的手工打點模式已經(jīng)不能滿足需求。如何在新的技術(shù)背景下讓前端數(shù)據(jù)采集工作更加完善、高效,是本文討論的重點。

[[262933]]

前端監(jiān)控數(shù)據(jù)采集

在采集數(shù)據(jù)之前,首先要考慮采集什么樣的數(shù)據(jù)。我們重點關(guān)注兩類數(shù)據(jù),一類是與用戶體驗相關(guān)的,如首屏?xí)r間、文件加載時間、頁面性能等;另外是幫助我們及時感知產(chǎn)品上線后是否出現(xiàn)異常的,比如資源錯誤、API 響應(yīng)時間等。具體來說,我們對前端的數(shù)據(jù)采集具體主要分為:

  • 路由切換 (href、hashchange、pushState)
  • JsError
  • 性能 (performance)
  • 資源錯誤
  • API
  • 日志上報

 路由切換

Vue、React、Angular 等前端技術(shù)的快速發(fā)展使單頁面應(yīng)用盛行。我們都知道,傳統(tǒng)的頁面應(yīng)用是用一些超鏈接來實現(xiàn)頁面切換和跳轉(zhuǎn)的,而單頁面應(yīng)用是使用各自的路由系統(tǒng)來管理前端的每一個頁面切換,例如 vue-router、react-router 等,跳轉(zhuǎn)時僅刷新局部資源 ,js、css 等公共資源只需要加載一次,這就使傳統(tǒng)網(wǎng)頁進(jìn)入離開的方式只有***次打開能被記錄。單頁應(yīng)用后續(xù)所有路由切換的方式有兩種,一種是 Hash,一種是 HTML5 推出的 History API。

1. href

href 為頁面初始化的***次進(jìn)入,這里只需要單純上報「進(jìn)入頁面」事件即可。

2. hashchange

Hash 路由一個明顯的標(biāo)志是帶有「 # 」。Hash 的優(yōu)勢是兼容性更好,但問題在于 URL 中一直存在「 # 」并不美觀。我們主要通過監(jiān)聽 URL 中的 hashchange 來捕獲具體的 hash 值進(jìn)行檢測。

 
 
 
 
  1. window.addEventListener('hashchange', function() { 
  2.     // 上報【進(jìn)入頁面】事件 
  3. }, true) 

需要注意的是,在新版 vue-router 中如果瀏覽器支持 history,即使 mode 選擇 hash 也會優(yōu)先選擇 history 模式,雖然表現(xiàn)形式暫時還是 # 號,但實際上是模擬的,所以千萬不要認(rèn)為自己在 mode 選擇了hash 就一定會是 hash。

3. History API

History 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法進(jìn)行路由切換,是目前主流的無刷新切換路由方式。與 hashchange 只能改變 # 后面的代碼片段相比,History API (pushState、replaceState) 給了前端完全的自由。

PopState 是瀏覽器返回事件的回調(diào),但是更新路由的 pushState、replaceState 并沒有回調(diào)事件,因此,還需要分別在 history.pushState() 和 history.replaceState() 方法里處理 URL 的變化。在這里,我們運用到了一種類似 Java 的 AOP 編程思想,對 pushState 和 replaceState 進(jìn)行改造。

AOP (Aspect-oriented programming)即面向切面編程,提倡針對同一類問題進(jìn)行統(tǒng)一處理。AOP 的核心思想是讓某個模塊能夠重用,它采用橫向抽取機制,將功能代碼從業(yè)務(wù)邏輯代碼中分離出來,擴展功能而不修改源代碼,相比封裝來說隔離得更加徹底。

下面介紹我們的具體改造方式:

 
 
 
 
  1. // ***階段:我們對原生方法進(jìn)行包裝,調(diào)用前執(zhí)行 dispatchEvent 了一個同樣的事件 
  2. function aop (type) { 
  3.     var source = window.history[type]; 
  4.     return function () { 
  5.         var event = new Event(type); 
  6.         event.arguments = arguments; 
  7.         window.dispatchEvent(event); 
  8.         var rewrite = source.apply(this, arguments); 
  9.         return rewrite; 
  10.     }; 
  11.  
  12. // 第二階段:將 pushState 和 replaceState 進(jìn)行基于 AOP 思想的代碼注入 
  13. window.history.pushState = aop('pushState'); 
  14. window.history.replaceState = aop('replaceState'); // 更改路由,不會留下歷史記錄 
  15.  
  16. // 第三階段:捕獲pushState 和 replaceState 
  17. window.addEventListener('pushState', function() { 
  18.     // 上報【進(jìn)入頁面】事件 
  19. }, true) 
  20. window.addEventListener('replaceState', function() { 
  21.     // 上報【進(jìn)入頁面】事件 
  22. }, true) 

window.history.pushState 實際調(diào)用關(guān)系如圖:

至此,我們對 pushState、replaceState 改造完畢,實現(xiàn)了有效地捕獲路由切換??梢钥吹剑覀冊诓磺秩霕I(yè)務(wù)代碼的情況下,對 window.history.pushState 進(jìn)行了擴展,在調(diào)用的同時會主動 dispatchEvent 一個 pushState。

但在這里我們也能看到一個弊端,就是如果 AOP 代理函數(shù)發(fā)生 JS 錯誤,將會阻斷后續(xù)的調(diào)用關(guān)系,使實際的 window.history.pushState 無法被調(diào)用。所以在使用此方式的時候,要對 AOP 代理函數(shù)的內(nèi)容做好完善的 try catch,來防止業(yè)務(wù)上出現(xiàn)異常。

*Tips:想自動捕獲頁面停留時間只需要在下一個進(jìn)入頁面事件觸發(fā)時,通過上一個頁面的打點時間和當(dāng)前時間做差值即可,這時候可以上報一個【離開頁面】事件。

 JsError

前端項目中,由于 JavaScript 本身是一個弱類型語言,加上瀏覽器環(huán)境的復(fù)雜性、網(wǎng)絡(luò)問題等,很容易發(fā)生錯誤。因此做好網(wǎng)頁錯誤監(jiān)控,不斷優(yōu)化代碼,提高代碼健壯性是一項很重要的工作。

JsError 的捕獲可以幫助我們分析和監(jiān)控線上問題,它與我們在 Chrome 瀏覽器的調(diào)試工具 Console 中看到的內(nèi)容一致。

1. window.onerror

我們使用 window.onerror 捕獲一般情況下 JS 錯誤的異常信息。捕獲 JS 錯誤的方式有兩種,window.onerror 和 window.addEventListener(‘error’)。一般情況下,捕獲 JS 異常不推薦使用 addEventListener(‘error’),主要是因為它沒有堆棧信息,而且還需要對捕獲到的信息做區(qū)分,因為它會將所有異常信息捕獲到,包括資源加載錯誤等。

 
 
 
 
  1. window.onerror = function (msg, url, lineno, colno, stack) { 
  2.     // 上報 【js錯誤】事件 

2. Uncaught (in promise)

當(dāng) Promise 內(nèi)發(fā)生 JS 錯誤或者 reject 信息未被業(yè)務(wù)處理的情況時,會拋出一個 unhandledrejection,并且這個錯誤不會被 window.onerror 以及 window.addEventListener('error')  捕獲,這里需要用專門的 window.addEventListener('unhandledrejection')  進(jìn)行捕獲處理:

 
 
 
 
  1. window.addEventListener('unhandledrejection', function (e) { 
  2.     var reg_url = /\(([^)]*)\)/; 
  3.     var fileMsg = e.reason.stack.split('\n')[1].match(reg_url)[1]; 
  4.     var fileArr = fileMsg.split(':'); 
  5.     var lineno = fileArr[fileArr.length - 2]; 
  6.     var colno = fileArr[fileArr.length - 1]; 
  7.     var url = fileMsg.slice(0, -lno.length - cno.length - 2);}, true); 
  8.     var msg = e.reason.message; 
  9.     // 上報 【js錯誤】事件 

我們注意到 unhandledrejection 因為繼承自 PromiseRejectionEvent,PromiseRejectionEvent 又繼承自 Event,所以 msg、url、lineno、colno、stack 以字符串形式放到了 e.reason.stack 中,我們需要解析出來上述參數(shù)來和 onerror 參數(shù)對齊,為后續(xù)監(jiān)控平臺的指標(biāo)統(tǒng)一化打下基礎(chǔ)。

3. 常見問題

  • "Script error."

如果出現(xiàn)捕獲的 msg 全部為 "Script error." ,問題在于你的 JS 地址和當(dāng)前網(wǎng)頁不在同一個域下。因為我們要經(jīng)常在線上的版本做靜態(tài)資源 CDN 化,會導(dǎo)致常訪問的頁面跟腳本文件來自不同的域名。這時如果沒有進(jìn)行額外的配置,瀏覽器出于安全方面的設(shè)計就容易出現(xiàn) "Script error."。我們可以利用目前流行的 Webpack 打包工具來處理此類問題。

 
 
 
 
  1. // webpack config 配置 
  2. // 處理 html 注入 js 添加跨域標(biāo)識 
  3. plugins: [ 
  4.     new HtmlWebpackPlugin({ 
  5.       filename: 'html/index.html', 
  6.       template: HTML_PATH, 
  7.       attributes: { 
  8.         crossorigin: 'anonymous' 
  9.       } 
  10.     }), 
  11.     new HtmlWebpackPluginCrossorigin({ 
  12.       inject: true 
  13.     }) 
  14.  
  15. // 處理按需加載的 js 添加跨域標(biāo)識 
  16. output: { 
  17.     crossOriginLoading: true 
  • SourceMap

大部分場景下,生產(chǎn)環(huán)境中的代碼都是經(jīng)過壓縮合并的,這使得我們捕獲到的錯誤很難映射到具體的源碼,為我們解決問題帶來很大困擾,這里簡要提出 2 個解決方案的思路。

生產(chǎn)環(huán)境我們需要添加 sourceMap 配置,這會導(dǎo)致安全隱患,因為這樣外網(wǎng)就可以通過 sourceMap 進(jìn)行源碼映射。為了降低風(fēng)險,我們可以通過如下方式:

  • 將 sourceMap 生成的 .map 文件設(shè)置公司內(nèi)網(wǎng)訪問,降低源碼安全風(fēng)險
  • 在發(fā)布代碼到 CDN 的時候,將 .map 文件存儲到公司內(nèi)網(wǎng)下

這時我們已經(jīng)擁有了 .map 文件,后續(xù)要做的就是通過捕獲到的 lineno、colno、url 調(diào)用 mozilla/source-map 庫進(jìn)行源碼映射,即可拿到真實的源碼錯誤信息。

 性能

性能指標(biāo)的獲取相對比較簡單,在 onload 之后讀取 window.performance 即可,里面包含了性能、內(nèi)存等信息。這部分內(nèi)容在很多現(xiàn)有的文章中都有介紹,因篇幅所限不在本文做過多展開,之后在相關(guān)主題文章中我們會有相關(guān)探討,感興趣的朋友可以添加「馬蜂窩技術(shù)」公眾號持續(xù)關(guān)注。

 資源錯誤

首先我們要明確下資源錯誤捕獲的使用場景,更多的是感知 DNS 劫持 及 CDN 節(jié)點異常等,具體方式如下:

 
 
 
 
  1. window.addEventListener('error', function (e) { 
  2.     var target = e.target || e.srcElement; 
  3.     if (target instanceof HTMLScriptElement) { 
  4.         // 上報 【資源錯誤】事件 
  5.     } 
  6. }, true) 

這里只做基本演示,實際環(huán)境中我們會關(guān)心更多的 Element 錯誤,如 css、img、woff 等,大家可以根據(jù)不同的場景自行添加。

*資源錯誤的使用場景更多依賴其他幾個維度,如:地域、運營商等,后續(xù)的篇幅中我們會具體講解。

 API

市面上主流的框架(如 Axios、jQuery.ajax 等)中,基本上所有的 API 請求都是基于xmlHttpRequest 或者 fetch,所以捕獲全局接口錯誤的方式就是封裝 xmlHttpRequest 或者 fetch。這里,我們的 SDK 仍然使用到上文提及的 AOP 思想,對 API 進(jìn)行攔截。

1. XmlHttpRequest

 
 
 
 
  1. var xhr = window.XMLHttpRequest; 
  2. var _open = xhr.prototype.open; 
  3. var _send = xhr.prototype.send; 
  4. var attr = {}; 
  5. var openReplacement = function (method, url) { 
  6.     // 可以存儲method、url、時間打點等信息 
  7.     attr.duration = new Date().getTime(); 
  8.     _open.apply(this, arguments); 
  9. var sendReplacement = function () { 
  10.     methods.addEvent(this, 'readystatechange', function (attr) { 
  11.         // 可以存儲response的status、計算客戶端實際響應(yīng)時間 
  12.         attr.status = this.status; 
  13.         attr.duration = new Date().getTime() - attr.duration; 
  14.         // 上報【API】事件 
  15.     }.bind(this, , JSON.parse(JSON.stringify(attr)))); 
  16.     _send.apply(this, arguments); 
  17. xmlhttp.prototype.open = openReplacement; 
  18. xmlhttp.prototype.send = sendReplacement; 

2. Fetch

 
 
 
 
  1. var _fetch = window.fetch; 
  2. window.fetch = function () { 
  3.     var attr = { 
  4.         method: arguments[1].method, 
  5.         url: arguments[0], 
  6.         duration: new Date().getTime() 
  7.     }; 
  8.  
  9.     return _fetch.apply(this, arguments).then(res => { 
  10.         attr.status = res.status; 
  11.         attr.duration = new Date().getTime() - attr.duration; 
  12.         // 上報【API】事件 
  13.         return res; 
  14.     }); 

需要注意的是,API 攔截一定要對 SDK 自己上報的 API 設(shè)置好忽略,否則將會導(dǎo)致循環(huán)上報問題。

 日志上報

為了監(jiān)控前端應(yīng)用是否正常運行,通常會在前端收集錯誤與性能等數(shù)據(jù),最終將這些數(shù)據(jù)上報到服務(wù)端。因為日志上報并不是應(yīng)用的主要功能邏輯,優(yōu)先級比較低,所以我們在確保日志數(shù)據(jù)上報更高效的同時,還應(yīng)該考慮如何盡可能地減少與其他關(guān)鍵操作的資源爭搶。

1. sendBeacon

navigator.sendBeacon() 方法主要用于滿足統(tǒng)計和診斷代碼的需要。這些代碼通常會在卸載文檔之前,嘗試通過 HTTP 將少量數(shù)據(jù)異步傳輸?shù)?Web 服務(wù)器。它解決了日志上報在 unload 時成功率很低的問題。我們在埋點時有很多對離開頁面時上報的需求,因為 SendBeacon 是異步的,不會影響當(dāng)前頁到下一個頁面的跳轉(zhuǎn)速度,可以更可靠地保障事件上報成功率,并且不影響路由切換。

 
 
 
 
  1. window.navigator.sendBeacon('上報事件的api', '數(shù)據(jù)參數(shù)') 

2. img.src

當(dāng)瀏覽器不支持 navigator.sendBeacon 時,我們可以采用模擬圖片加載的方式發(fā)送日志上報事件,且不會存在跨域問題。

 
 
 
 
  1. var img = new Image(); 
  2. img.src = API + '?' + '數(shù)據(jù)參數(shù)' 

3. 關(guān)于 XmlHttpRequest

這里不推薦用 XmlHttpRequest。XHR 雖然支持異步請求,直接發(fā)送數(shù)據(jù)到后端,但是會受到跨域和同源的限制。而通過日志上報 API 跟業(yè)務(wù)是不在一個域下的,如果采用這種模式需要設(shè)置 Access-Control-Allow-Origin:* 跨域,非常不方便,并且在 unload 情況下上報發(fā)生的丟包率***。

總結(jié)來看,日志上報推薦采用 sendBeacon -> img.src。在不影響用戶路由切換和阻塞用戶的情況下丟包率可以控制在 10%-30%,具體要看用戶群體對應(yīng)的環(huán)境。

小結(jié)

高效的前端數(shù)據(jù)采集對于搭建前端監(jiān)控平臺來說非常關(guān)鍵。本文我們分享了馬蜂窩在保證數(shù)據(jù)采集及時、準(zhǔn)確、全面等方面的一些思路和實踐。需要提示大家注意的是,文中涉及到的演示只做了核心代碼的關(guān)鍵描述,不具備生產(chǎn)使用,我們在實際使用中需要做好兼容及容錯。

本文也將作為馬蜂窩前端監(jiān)控平臺系列文章的開篇,今后還將陸續(xù)推出埋點模式、數(shù)據(jù)處理和分析、報警以及監(jiān)控平臺在具體業(yè)務(wù)中的應(yīng)用等內(nèi)容,歡迎大家持續(xù)關(guān)注。


文章題目:讓前端監(jiān)控數(shù)據(jù)采集更高效
URL標(biāo)題:http://m.5511xx.com/article/cdspcoj.html