1. 程式人生 > 其它 >axios原始碼解析 - 請求攔截器

axios原始碼解析 - 請求攔截器

axios請求攔截器,也就是在請求傳送之前執行自定義的函式。

axios原始碼版本 - ^0.27.2 (原始碼是精簡版)

平時在業務中會這樣去寫請求攔截器,程式碼如下:

// 建立一個新的例項
var service = axios.create();

// 請求攔截器
service.interceptors.request.use((config) => {
  // 請求頭加token
  config.headers['token'] = 'xxx';
  ... ... ...
 
  return config;
}, (err) => {
  return Promise.reject(err);
});

 其中 service.interceptors.request.use 方法起到了作用,其核心原始碼如下:

/* axios/core/Axios.js */
// Axios建構函式
function Axios(defaultConfig) {
  this.defaults = defaultConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  }
}

/* axios/core/InterceptorManager.js */
//
InterceptorManager建構函式 function InterceptorManager() { // 預設空陣列 this.handlers= []; } // InterceptorManager原型上定義use方法 (上述業務中的use方法,其實就是呼叫了該方法) InterceptorManager.prototype.use = function(fulfilled, rejected) { // 陣列中push一個包含成功回撥、失敗回撥的物件 this.handlers.push({ fulfilled: fulfilled, rejected: rejected });
// 返回陣列長度 - 1 return this.handlers.length - 1; } // InterceptorManager原型上定義eject方法 InterceptorManager.prototype.eject = function(id) { if (this.handlers[id]) { this.handlers[id] = null; } } // InterceptorManager原型上定義forEach方法 InterceptorManager.prototype.forEach = function(fn) { utils.forEach(this.handlers, function(h) { if (h !== null) { fn(h); } }); }

service.interceptors.request.use 原來就是向handlers陣列push了一個物件,可列印資訊檢視,程式碼如下:

console.log(service.interceptors.request.handlers);
// 結果如下
[
  {
    fulfilled: (config) => {...},
    rejedcted: (err) => {...}
  }
]

那麼,在傳送請求時,請求攔截器是如何運作的,程式碼如下:

Axios.prototype.request = function(defaultConfigOrUrl, config) {
  ... ... ...

  var requestInterceptorChain = [];
  this.interceptors.request.forEach(function (interceptor) {
    // 將該例項的this.this.interceptors.request.handlers放入requestChain 
    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  var promise;

  // dispatchRequest就是請求過程
  var chain = [dispatchRequest, undefined];
  Array.prototype.unshift.apply(chain, requestInterceptorChain);

  promise = Promise.resolve(config);
  while (chain.length) {
    // 鏈式呼叫,不斷減少chain陣列的長度,直至為空
    promise = promise.then(chain.shift(), chain.shift());
  }

  return promise;

  ... ... ...   
}

這也便是說為什麼axios是基於promise的,請求攔截器 --> 請求 --> 響應攔截器。

取消攔截器

取消攔截器功能,作者覺得作用不大,程式碼如下:

var requestNumber = service.interceptors.request.use(fulfilled, rejected);

// 取消請求攔截器
service.interceptors.request.reject(requestNumber);

service.post({})

多個請求攔截器

主要講多個請求攔截器的執行順序

// 第一個請求攔截器
service.interceptors.request.use(fulfilled1, rejected1);

// 第二個請求攔截器
service.interceptors.request.use(fulfilled2, rejected2);

// 第三個請求攔截器
service.interceptors.request.use(fulfilled3, rejected3);

// 根據上述Axios.prototype.request方法,可以知道handlers陣列:[fulfilled3, rejected3, fulfilled2, rejected2, fulfilled1, rejected1]

// 所以執行順序:fulfilled3 --> fulfilled2 --> fulfilled1