摘要:參考一步一步搭建前端監(jiān)控系統(tǒng)錯(cuò)誤監(jiān)控篇用插件記錄網(wǎng)絡(luò)請(qǐng)求異常關(guān)于專注于微信小程序微信小游戲支付寶小程序和線上應(yīng)用實(shí)時(shí)監(jiān)控。
摘要: 如何監(jiān)控HTTP請(qǐng)求錯(cuò)誤?
作者:一步一個(gè)腳印一個(gè)坑
原文:搭建前端監(jiān)控系統(tǒng)(四)接口請(qǐng)求異常監(jiān)控篇
Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。
背景:市面上的監(jiān)控系統(tǒng)有很多,大多收費(fèi),對(duì)于小型前端項(xiàng)目來說,必然是痛點(diǎn)。另一點(diǎn)主要原因是,功能雖然通用,卻未必能夠滿足我們自己的需求, 所以我們自給自足也許是個(gè)不錯(cuò)的辦法。
這是搭建前端監(jiān)控系統(tǒng)的第四章,主要是介紹如何統(tǒng)計(jì)靜態(tài)資源加載報(bào)錯(cuò),跟著我一步步做,你也能搭建出一個(gè)屬于自己的前端監(jiān)控系統(tǒng)。
上一章介紹了如何統(tǒng)計(jì)靜態(tài)資源加載報(bào)錯(cuò),今天要說的是接口請(qǐng)求報(bào)錯(cuò)。可能有人會(huì)認(rèn)為接口的報(bào)錯(cuò)應(yīng)該由后臺(tái)來關(guān)注,統(tǒng)計(jì),并修復(fù)。 確實(shí)如此,而且后臺(tái)服務(wù)有了很多成熟完善的統(tǒng)計(jì)工具,完全能夠應(yīng)對(duì)大部分的異常情況, 那么為什么還需要前端對(duì)接口請(qǐng)求進(jìn)行監(jiān)控呢。原因很簡單,因?yàn)榍岸耸莃ug的第一發(fā)現(xiàn)位置,在你幫后臺(tái)背鍋之前怎么快速把過甩出去呢,這時(shí)候,我們就需要有一個(gè)接口的監(jiān)控系統(tǒng),哈哈 :)
我們要監(jiān)控接口報(bào)錯(cuò)的情況,及時(shí)定位線上問題產(chǎn)生的原因
我們要分析接口的性能,以輔助我們對(duì)前端應(yīng)用的優(yōu)化。
好了, 進(jìn)入正題吧:
如何監(jiān)控前端接口請(qǐng)求呢?
一般前端請(qǐng)求都是用jquery的ajax請(qǐng)求,也有用fetch請(qǐng)求的,以及前端框架自己封裝的請(qǐng)求等等。總之他們封裝的方法各不相同,但是萬變不離其宗,他們都是對(duì)瀏覽器的這個(gè)對(duì)象 window.XMLHttpRequest 進(jìn)行了封裝,所以我們只要能夠監(jiān)聽到這個(gè)對(duì)象的一些事件,就能夠把請(qǐng)求的信息分離出來。
如何監(jiān)聽ajax請(qǐng)求如果你用的jquery、zepto、或者自己封裝的ajax方法,就可以用如下的方法進(jìn)行監(jiān)聽。我們監(jiān)聽 XMLHttpRequest 對(duì)象的兩個(gè)事件 loadstart, loadend。但是監(jiān)聽的結(jié)果并不是像我們想象的那么容易理解,我們先看下ajaxLoadStart,ajaxLoadEnd的回調(diào)方法。
/** * 頁面接口請(qǐng)求監(jiān)控 */ function recordHttpLog() { // 監(jiān)聽ajax的狀態(tài) function ajaxEventTrigger(event) { var ajaxEvent = new CustomEvent(event, { detail: this }); window.dispatchEvent(ajaxEvent); } var oldXHR = window.XMLHttpRequest; function newXHR() { var realXHR = new oldXHR(); realXHR.addEventListener( "loadstart", function() { ajaxEventTrigger.call(this, "ajaxLoadStart"); }, false ); realXHR.addEventListener( "loadend", function() { ajaxEventTrigger.call(this, "ajaxLoadEnd"); }, false ); // 此處的捕獲的異常會(huì)連日志接口也一起捕獲,如果日志上報(bào)接口異常了,就會(huì)導(dǎo)致死循環(huán)了。 // realXHR.onerror = function () { // siftAndMakeUpMessage("Uncaught FetchError: Failed to ajax", WEB_LOCATION, 0, 0, {}); // } return realXHR; } var timeRecordArray = []; window.XMLHttpRequest = newXHR; window.addEventListener("ajaxLoadStart", function(e) { var tempObj = { timeStamp: new Date().getTime(), event: e }; timeRecordArray.push(tempObj); }); window.addEventListener("ajaxLoadEnd", function() { for (var i = 0; i < timeRecordArray.length; i++) { if (timeRecordArray[i].event.detail.status > 0) { var currentTime = new Date().getTime(); var url = timeRecordArray[i].event.detail.responseURL; var status = timeRecordArray[i].event.detail.status; var statusText = timeRecordArray[i].event.detail.statusText; var loadTime = currentTime - timeRecordArray[i].timeStamp; if (!url || url.indexOf(HTTP_UPLOAD_LOG_API) != -1) return; var httpLogInfoStart = new HttpLogInfo( HTTP_LOG, url, status, statusText, "發(fā)起請(qǐng)求", timeRecordArray[i].timeStamp, 0 ); httpLogInfoStart.handleLogInfo(HTTP_LOG, httpLogInfoStart); var httpLogInfoEnd = new HttpLogInfo( HTTP_LOG, url, status, statusText, "請(qǐng)求返回", currentTime, loadTime ); httpLogInfoEnd.handleLogInfo(HTTP_LOG, httpLogInfoEnd); // 當(dāng)前請(qǐng)求成功后就在數(shù)組中移除掉 timeRecordArray.splice(i, 1); } } }); }
一個(gè)頁面上會(huì)有很多個(gè)請(qǐng)求,當(dāng)一個(gè)頁面發(fā)出多個(gè)請(qǐng)求的時(shí)候,ajaxLoadStart事件被監(jiān)聽到,但是卻無法區(qū)分出來到底發(fā)送的是哪個(gè)請(qǐng)求,只返回了一個(gè)內(nèi)容超多的事件對(duì)象,而且事件對(duì)象的內(nèi)容幾乎完全一樣。當(dāng)ajaxLoadEnd事件被監(jiān)聽到的時(shí)候,也會(huì)返回一個(gè)內(nèi)容超多的時(shí)間對(duì)象,這個(gè)時(shí)候事件對(duì)象里包含了接口請(qǐng)求的所有信息。幸運(yùn)的是,兩個(gè)對(duì)象是同一個(gè)引用,也就意味著,ajaxLoadStart和ajaxLoadEnd事件被捕獲的時(shí)候,他們作用的是用一個(gè)對(duì)象。那我們就有辦法分析出來了。
當(dāng)ajaxLoadStart事件發(fā)生的時(shí)候,我們將回調(diào)方法中的事件對(duì)象全都放進(jìn)數(shù)組timeRecordArray里,當(dāng)ajaxLoadEnd發(fā)生的時(shí)候,我們就去遍歷這個(gè)數(shù)據(jù),遇到又返回結(jié)果的事件對(duì)象,說明接口請(qǐng)求已經(jīng)完成,記錄下來,并從數(shù)組中刪除該事件對(duì)象。這樣我們就能夠逐一分析出接口請(qǐng)求的內(nèi)容了。
如何監(jiān)聽fetch請(qǐng)求通過第一種方法,已經(jīng)能夠監(jiān)聽到大部分的ajax請(qǐng)求了。然而,使用fetch請(qǐng)求的人越來越多,因?yàn)閒etch的鏈?zhǔn)秸{(diào)用可以讓我們擺脫ajax的嵌套地獄,被更多的人所青睞。奇怪的是,我用第一種方式,卻無法監(jiān)聽到fetch的請(qǐng)求事件,這是為什么呢?
return new Promise(function(resolve, reject) { var request = new Request(input, init); var xhr = new XMLHttpRequest(); xhr.onload = function() { var options = { status: xhr.status, statusText: xhr.statusText, headers: parseHeaders(xhr.getAllResponseHeaders() || "") }; options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL"); var body = "response" in xhr ? xhr.response : xhr.responseText; resolve(new Response(body, options)); }; // ....... xhr.send( typeof request._bodyInit === "undefined" ? null : request._bodyInit ); });
這個(gè)是fetch的一段源碼, 可以看到,它創(chuàng)建了一個(gè)Promise, 并新建了一個(gè)XMLHttpRequest對(duì)象 var xhr =newXMLHttpRequest()。由于fetch的代碼是內(nèi)置在瀏覽器中的,它必然先用監(jiān)控代碼執(zhí)行,所以,我們?cè)谔砑颖O(jiān)聽事件的時(shí)候,是無法監(jiān)聽fetch里邊的XMLHttpRequest對(duì)象的。怎么辦呢,我們需要重寫一下fetch的代碼。只要在監(jiān)控代碼執(zhí)行之后,我們重寫一下fetch,就可以正常監(jiān)聽使用fetch方式發(fā)送的請(qǐng)求了。就這么簡單 :)
看一下需要監(jiān)聽的字段:
// 設(shè)置日志對(duì)象類的通用屬性 function setCommonProperty() { this.happenTime = new Date().getTime(); // 日志發(fā)生時(shí)間 this.webMonitorId = WEB_MONITOR_ID; // 用于區(qū)分應(yīng)用的唯一標(biāo)識(shí)(一個(gè)項(xiàng)目對(duì)應(yīng)一個(gè)) this.simpleUrl = window.location.href.split("?")[0].replace("#", ""); // 頁面的url this.completeUrl = utils.b64EncodeUnicode( encodeURIComponent(window.location.href) ); // 頁面的完整url this.customerKey = utils.getCustomerKey(); // 用于區(qū)分用戶,所對(duì)應(yīng)唯一的標(biāo)識(shí),清理本地?cái)?shù)據(jù)后失效, // 用戶自定義信息, 由開發(fā)者主動(dòng)傳入, 便于對(duì)線上問題進(jìn)行準(zhǔn)確定位 var wmUserInfo = localStorage.wmUserInfo ? JSON.parse(localStorage.wmUserInfo) : ""; this.userId = utils.b64EncodeUnicode(wmUserInfo.userId || ""); this.firstUserParam = utils.b64EncodeUnicode( wmUserInfo.firstUserParam || "" ); this.secondUserParam = utils.b64EncodeUnicode( wmUserInfo.secondUserParam || "" ); } // 接口請(qǐng)求日志,繼承于日志基類MonitorBaseInfo function HttpLogInfo( uploadType, url, status, statusText, statusResult, currentTime, loadTime ) { setCommonProperty.apply(this); this.uploadType = uploadType; // 上傳類型 this.httpUrl = utils.b64EncodeUnicode(encodeURIComponent(url)); // 請(qǐng)求地址 this.status = status; // 接口狀態(tài) this.statusText = statusText; // 狀態(tài)描述 this.statusResult = statusResult; // 區(qū)分發(fā)起和返回狀態(tài) this.happenTime = currentTime; // 客戶端發(fā)送時(shí)間 this.loadTime = loadTime; // 接口請(qǐng)求耗時(shí) }
所有工作準(zhǔn)備完畢,如果把收集到的日志從不同的維度展現(xiàn)出來,我就不細(xì)說了,直接上圖了。如此,便能夠?qū)η岸私涌趫?bào)錯(cuò)的情況有一個(gè)清晰的了解,也能夠快速的發(fā)現(xiàn)線上的問題。
參考一步一步搭建前端監(jiān)控系統(tǒng):JS錯(cuò)誤監(jiān)控篇
用Fundebug插件記錄網(wǎng)絡(luò)請(qǐng)求異常
關(guān)于FundebugFundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應(yīng)用實(shí)時(shí)BUG監(jiān)控。 自從2016年雙十一正式上線,F(xiàn)undebug累計(jì)處理了10億+錯(cuò)誤事件,付費(fèi)客戶有陽光保險(xiǎn)、核桃編程、荔枝FM、掌門1對(duì)1、微脈、青團(tuán)社等眾多品牌企業(yè)。歡迎大家免費(fèi)試用!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/105613.html
摘要:摘要通過記錄用戶行為,快速復(fù)現(xiàn)場(chǎng)景。這是搭建前端監(jiān)控系統(tǒng)的第二章,主要是介紹如何統(tǒng)計(jì)報(bào)錯(cuò),跟著我一步步做,你也能搭建出一個(gè)屬于自己的前端監(jiān)控系統(tǒng)。 摘要: 通過記錄用戶行為,快速復(fù)現(xiàn)BUG場(chǎng)景。 作者:一步一個(gè)腳印一個(gè)坑 原文:搭建前端監(jiān)控系統(tǒng)(備選)用戶行為統(tǒng)計(jì)和監(jiān)控篇(如何快速定位線上問題) Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 一步一步搭建前端監(jiān)控系統(tǒng)系列博客: ...
摘要:一直以來,前端的線上問題很難定位,因?yàn)樗l(fā)生于用戶的一系列操作之后。當(dāng)然,這些問題并非不能克服,讓我們來一起看看如何去定位線上的問題吧。地址參考一步一步搭建前端監(jiān)控系統(tǒng)錯(cuò)誤監(jiān)控篇一步一步搭建前端監(jiān)控系統(tǒng)接口請(qǐng)求異常監(jiān)控篇 摘要: 記錄用戶行為,排查線上BUG。 作者:一步一個(gè)腳印一個(gè)坑 原文:如何定位前端線上問題(如何排查前端生產(chǎn)問題) Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所...
摘要:摘要徒手寫錯(cuò)誤監(jiān)控。為什么用定時(shí)器呢,因?yàn)樵趩雾搼?yīng)用中,路由的切換和地址欄的變化是無法被監(jiān)控的,我確實(shí)沒有想到特別好的辦法來監(jiān)控,所以用了這種方式,如果有人有更好的辦法,請(qǐng)給我留言,謝謝。 摘要: 徒手寫JS錯(cuò)誤監(jiān)控。 作者:一步一個(gè)腳印一個(gè)坑 原文:搭建前端監(jiān)控系統(tǒng)(二)JS錯(cuò)誤監(jiān)控篇 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 背景:市面上的監(jiān)控系統(tǒng)有很多,大多收費(fèi),對(duì)于...
摘要:故而,我們需要在項(xiàng)目出現(xiàn)異常時(shí)主動(dòng)對(duì)其進(jìn)行收集上報(bào),分析原因和影響后制定下一步解決方案。所以,我們需要一款成熟的異常監(jiān)控系統(tǒng)來協(xié)助我們。最近在公司項(xiàng)目中部署了,用于項(xiàng)目中異常監(jiān)控,涵蓋了前端后端。 原文首發(fā)于我的個(gè)人博客: https://lonhon.top/ 凡事只要有可能出錯(cuò),那就一定會(huì)出錯(cuò) 對(duì)于任何一個(gè)項(xiàng)目而言,本地測(cè)試肯定做不到100%覆蓋,而且,我們也不能保證用戶能按照我們...
摘要:目前已經(jīng)在運(yùn)行的線上前端監(jiān)控系統(tǒng)代碼和講解都放在這篇文章里監(jiān)控系統(tǒng)介紹及代碼用戶對(duì)前端程序員來說,就是一個(gè)黑匣子。 摘要: 通過錄屏或者截圖,快速復(fù)現(xiàn)BUG場(chǎng)景。 作者:一步一個(gè)腳印一個(gè)坑 原文:搭建前端監(jiān)控系統(tǒng)(備選)Js截圖上報(bào)篇 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 PS:本文關(guān)于Fundebug錄屏功能的內(nèi)容有些不準(zhǔn)確的地方,比如錄屏并非通過截圖實(shí)現(xiàn)的,錄屏插件...
閱讀 3408·2023-04-25 20:37
閱讀 3149·2021-09-07 09:59
閱讀 1673·2019-08-29 12:43
閱讀 1193·2019-08-28 18:27
閱讀 487·2019-08-26 13:50
閱讀 2037·2019-08-26 10:33
閱讀 3601·2019-08-23 18:39
閱讀 2404·2019-08-23 18:09