前端監控數據收集(請求攔截)

所謂web,即便你我素未謀面,便知志趣相投;足不出戶,亦知世界之大。git

01 — 爲何攔截請求

如今的web應用,大都是經過請求(http)去獲取資源,拿到資源後再呈現給用戶,一個頁面中能夠有多個這樣的請求。每一次請求的開始,等待,完成,異常都會有相應的狀態來標識。咱們在本身的框架中一般都會使用一個全局過濾器,來攔截請求,目的大同小異:github

  • 在發送請求以前,修改請求參數,添加請求頭
  • 請求發送中的進度計算(一般是文件上傳)
  • 請求出錯後的捕獲
  • 請求結束後,處理後臺返回數據結構,進行適配
  • ……

看看請求的整個流程圖:web

圖片描述

而咱們最經常使用的發送請求的即是XMLHttpRequest。瀏覽器

XMLHttpRequest.readyState的五種就緒狀態:服務器

  • 0:請求未初始化(尚未調用 open())。
  • 1:請求已經創建,可是尚未發送(尚未調用 send())。
  • 2:請求已發送,正在處理中(一般如今能夠從響應中獲取內容頭)。
  • 3:請求在處理中;一般響應中已有部分數據可用了,可是服務器尚未完成響應的生成。
  • 4:響應已完成;您能夠獲取並使用服務器的響應了。

而且XMLHttpRequest還提供了每一個階段的事件:網絡

  • abort

    若是請求停止,會觸發abort事件。數據結構

  • error

    網絡錯誤(如太多重定向)會阻止請求完成,會觸發error事件。app

  • load

    當事件完成,會觸發load事件。框架

  • loadend

    當一個請求完成,不管成功(load)或者不成功(abort/error)後觸發ide

  • loadstart

    當調用send()時,觸發單個loadstart事件。

  • progress

    當等待服務器的響應時,XHR對象會發生progress事件。一般每隔50毫秒左右,因此可使用這事件給用戶反饋請求的進度。

  • timeout

    當等待服務器的響應超時會觸發。

02 — 如何攔截請求

瞭解了XMLHttpRequest的請求流程後,咱們就能夠開始去攔截瀏覽器發出的請求,去作咱們想作的事。

方式一:

(function (xhr) {
// Capture request before any network activity occurs:
  var send = xhr.send;
  xhr.send = function (data) {
  this.addEventListener('loadstart', onLoadStart);
  this.addEventListener('loadend', onLoadEnd);
  this.addEventListener('error', onError);
  return send.apply(this, arguments);
  };
})(XMLHttpRequest.prototype);

這種是最簡單直接的方式,修改XMLHttpRequest的原型,在發送請求時開啓事件監聽。大多數狀況下都是沒什麼大問題的,但後來發如今Angular4+以上版本中這樣去攔截,請求觸發loadend事件後獲取到的請求響應成功與否狀態始終爲false,由於Angualr2後來的版本也使用事件監聽來處理攔截,有些地方就衝突了。

方式二:

出現問題總要解決吧,而後就採用方法一的升級版本,徹底重寫XMLHttpRequest。

(function () {
  // create XMLHttpRequest proxy object
  var oldXMLHttpRequest = XMLHttpRequest;
  // define constructor for my proxy object
  window.XMLHttpRequest = function () {
    var actual = new oldXMLHttpRequest();
    var self = this;
    this.onreadystatechange = null;
    // this is the actual handler on the real XMLHttpRequest object
    actual.onreadystatechange = function () {
      if (this.readyState == 1) {
      onLoadStart.call(this);
      } else if (this.readyState == 4) {
        if(this.status==200)
           onLoadEnd.call(this);
        else{
           onError.call(this);
        }
      }
     if (self.onreadystatechange) {
        return self.onreadystatechange();
      }
    };
​
​
// add all proxy getters
["status", "statusText", "responseType", "response",
"readyState", "responseXML", "upload"
].forEach(function (item) {
  Object.defineProperty(self, item, {
  get: function () {
    return actual[item];
   },
  set: function (val) {
    actual[item] = val;
  }
  });
});
​
​
// add all proxy getters/setters
["ontimeout, timeout", "withCredentials", "onload", "onerror", "onprogress"].forEach(function (item) {
  Object.defineProperty(self, item, {
    get: function () {
      return actual[item];
    },
    set: function (val) {
      actual[item] = val;
    }
  });
});
​
​
// add all pure proxy pass-through methods
["addEventListener", "send", "open", "abort", "getAllResponseHeaders",
"getResponseHeader", "overrideMimeType", "setRequestHeader", "removeEventListener"
].forEach(function (item) {
  Object.defineProperty(self, item, {
    value: function () {
      return actual[item].apply(actual, arguments);
    }
   });
  });
  }
})();

03 — 項目實戰

如今咱們能夠放心的攔截瀏覽器發出的請求了,媽媽不再用擔憂個人學習了,哈哈。說一千道一萬,來點乾貨,直接看項目。

傳送門:web-monitor

圖片描述


喜歡請點個讚唄

或者去https://github.com/kisslove/w... Star一下

或者打賞一下

再或者……

哈哈,想法有點多了。

圖片描述

相關文章
相關標籤/搜索