国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

讓前端監控數據采集更高效

Half / 753人閱讀

摘要:如何在新的技術背景下讓前端數據采集工作更加完善高效,是本文討論的重點。具體來說,我們對前端的數據采集具體主要分為路由切換性能資源錯誤日志上報路由切換等前端技術的快速發展使單頁面應用盛行。

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

搭建一套前端監控平臺需要考慮的方面很多,比如數據采集、埋點模式、數據處理和分析、報警以及監控平臺在具體業務中的應用等等。在這所有環節中,準確、完整、全面的數據采集是一切的前提,也為后續的用戶精細化運營提供基礎。

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

前端監控數據采集

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

路由切換 (href、hashchange、pushState)

JsError

性能 (performance)

資源錯誤

API

日志上報

路由切換

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

1. href

href 為頁面初始化的第一次進入,這里只需要單純上報「進入頁面」事件即可。

2. hashchange

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

window.addEventListener("hashchange",?function()?{
????//?上報【進入頁面】事件
},?true)

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

3. History API

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

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

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

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

//?第一階段:我們對原生方法進行包裝,調用前執行?dispatchEvent?了一個同樣的事件
function?aop?(type)?{
????var?source?=?window.history[type];
????return?function?()?{
????????var?event?=?new?Event(type);
????????event.arguments?=?arguments;
????????window.dispatchEvent(event);
????????var?rewrite?=?source.apply(this,?arguments);
????????return?rewrite;
????};
}

//?第二階段:將?pushState?和?replaceState?進行基于?AOP?思想的代碼注入
window.history.pushState?=?aop("pushState");
window.history.replaceState?=?aop("replaceState");?//?更改路由,不會留下歷史記錄

//?第三階段:捕獲pushState?和?replaceState
window.addEventListener("pushState",?function()?{
????//?上報【進入頁面】事件
},?true)
window.addEventListener("replaceState",?function()?{
????//?上報【進入頁面】事件
},?true)

window.history.pushState 實際調用關系如圖:

至此,我們對 pushState、replaceState 改造完畢,實現了有效地捕獲路由切換。可以看到,我們在不侵入業務代碼的情況下,對 window.history.pushState 進行了擴展,在調用的同時會主動 dispatchEvent 一個 pushState。

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

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

JsError

前端項目中,由于 JavaScript 本身是一個弱類型語言,加上瀏覽器環境的復雜性、網絡問題等,很容易發生錯誤。因此做好網頁錯誤監控,不斷優化代碼,提高代碼健壯性是一項很重要的工作。

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

1. window.onerror

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

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

2. Uncaught (in promise)

當 Promise 內發生 JS 錯誤或者 reject 信息未被業務處理的情況時,會拋出一個 unhandledrejection,并且這個錯誤不會被 window.onerror 以及 window.addEventListener("error") ?捕獲,這里需要用專門的 window.addEventListener("unhandledrejection") ?進行捕獲處理:

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

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

3.?常見問題

"Script error."

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

//?webpack?config?配置
//?處理?html?注入?js?添加跨域標識
plugins:?[
????new?HtmlWebpackPlugin({
??????filename:?"html/index.html",
??????template:?HTML_PATH,
??????attributes:?{
????????crossorigin:?"anonymous"
??????}
????}),
????new?HtmlWebpackPluginCrossorigin({
??????inject:?true
????})
]

//?處理按需加載的?js?添加跨域標識
output:?{
????crossOriginLoading:?true
}

SourceMap

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

生產環境我們需要添加 sourceMap 配置,這會導致安全隱患,因為這樣外網就可以通過 sourceMap 進行源碼映射。為了降低風險,我們可以通過如下方式:

將 sourceMap 生成的 .map 文件設置公司內網訪問,降低源碼安全風險

在發布代碼到 CDN 的時候,將 .map 文件存儲到公司內網下

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

性能

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

資源錯誤

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

window.addEventListener("error",?function?(e)?{
????var?target?=?e.target?||?e.srcElement;
????if?(target?instanceof?HTMLScriptElement)?{
????????//?上報?【資源錯誤】事件
????}
},?true)

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

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

API

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

1. XmlHttpRequest

var?xhr?=?window.XMLHttpRequest;
var?_open?=?xhr.prototype.open;
var?_send?=?xhr.prototype.send;
var?attr?=?{};
var?openReplacement?=?function?(method,?url)?{
????//?可以存儲method、url、時間打點等信息
????attr.duration?=?new?Date().getTime();
????_open.apply(this,?arguments);
}
var?sendReplacement?=?function?()?{
????methods.addEvent(this,?"readystatechange",?function?(attr)?{
????????//?可以存儲response的status、計算客戶端實際響應時間
????????attr.status?=?this.status;
????????attr.duration?=?new?Date().getTime()?-?attr.duration;
????????//?上報【API】事件
????}.bind(this,?,?JSON.parse(JSON.stringify(attr))));
????_send.apply(this,?arguments);
}
xmlhttp.prototype.open?=?openReplacement;
xmlhttp.prototype.send?=?sendReplacement;

2. Fetch

需要注意的是,API 攔截一定要對 SDK 自己上報的 API 設置好忽略,否則將會導致循環上報問題。

var?_fetch?=?window.fetch;
window.fetch?=?function?()?{
????var?attr?=?{
????????method:?arguments[1].method,
????????url:?arguments[0],
????????duration:?new?Date().getTime()
????};

????return?_fetch.apply(this,?arguments).then(res?=>?{
????????attr.status?=?res.status;
????????attr.duration?=?new?Date().getTime()?-?attr.duration;
????????//?上報【API】事件
????????return?res;
????});
}
日志上報

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

1. sendBeacon

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

window.navigator.sendBeacon("上報事件的api",?"數據參數")

2. img.src

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

var?img?=?new?Image();
img.src?=?API?+?"?"?+?"數據參數"

3. 關于 XmlHttpRequest

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

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

小結

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

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

本文作者:王崢,馬蜂窩大數據平臺前端技術專家。

(馬蜂窩技術原創內容,轉載務必注明出處保存文末二維碼圖片,謝謝配合。)

關注馬蜂窩技術,找到更多你想要的內容

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103660.html

相關文章

  • 與眾不同的快速開發平臺 —— 簡潔高效的wueasy軟件

    摘要:當其他人在浪費時間的時候,因為有了它,你可以與時間賽跑,在有限的生命中取得更好的價值當其他人在刷著抖音和快手時,因為有了它,你可以簡單工作,開心工作,享受工作當其他人在羨慕你取得成功時,你可以驕傲的說,它是我最得意的伴侶,一款讓你可以讓放心 當其他人在浪費時間的時候,因為有了它,你可以與時間賽跑,在有限的生命中取得更好的價值 當其他人在刷著抖音和快手時,因為有了它,你可以簡單工作,開...

    archieyang 評論0 收藏0
  • [ 好文分享 ] 美團酒店Node全棧開發實踐

    摘要:我所在的美團酒店事業部去年月份成立,新的業務新的開發團隊,這一切使得我們的前后端分離推進的很徹底。日志監控平臺日志監控平臺是美團內部的一個日志收集系統,目前美團統一使用收集日志,具有接收格式日志的能力,而日志監控平臺也是以格式日志來收集。 轉自:美團技術團隊 作者:美團技術團隊 分享理由:很好的分享,可見,基于Node的前后端分離的架構是越顯流行和重要,前端攻城獅們,No...

    wangdai 評論0 收藏0
  • 馬蜂窩容器化平臺前端賦能實踐

    摘要:本文將結合馬蜂窩容器化平臺賦能前端應用構建的實踐經驗,介紹整個平臺背后的設計和實現原理,取得的一些效果及問題的優化方案。如果使用容器化平臺就不會出現這方面的擔憂。 容器對前端開發真的有用嗎?答案是肯定的。 最初當我向公司的前端同學「安利」容器技術的時候,很多人都會說:「容器?這不是用在后端的技術嗎?我不懂啊,而且前端開發用不上吧。」 showImg(https://segmentfau...

    wall2flower 評論0 收藏0
  • 馬蜂窩容器化平臺前端賦能實踐

    摘要:本文將結合馬蜂窩容器化平臺賦能前端應用構建的實踐經驗,介紹整個平臺背后的設計和實現原理,取得的一些效果及問題的優化方案。如果使用容器化平臺就不會出現這方面的擔憂。 容器對前端開發真的有用嗎?答案是肯定的。 最初當我向公司的前端同學「安利」容器技術的時候,很多人都會說:「容器?這不是用在后端的技術嗎?我不懂啊,而且前端開發用不上吧。」 showImg(https://segmentfau...

    余學文 評論0 收藏0
  • 馬蜂窩容器化平臺前端賦能實踐

    摘要:本文將結合馬蜂窩容器化平臺賦能前端應用構建的實踐經驗,介紹整個平臺背后的設計和實現原理,取得的一些效果及問題的優化方案。如果使用容器化平臺就不會出現這方面的擔憂。 容器對前端開發真的有用嗎?答案是肯定的。 最初當我向公司的前端同學「安利」容器技術的時候,很多人都會說:「容器?這不是用在后端的技術嗎?我不懂啊,而且前端開發用不上吧。」 showImg(https://segmentfau...

    desdik 評論0 收藏0

發表評論

0條評論

Half

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<