一、Axios的攔截器能干些什么?
Axios攔截器的實現原理主要涉及兩個方面:請求攔截器和響應攔截器,它們分別在請求發送前和響應返回后進行預處理和后處理。
Axios內部維護了兩個數組,一個用于存儲請求攔截器,另一個用于存儲響應攔截器。每個攔截器都是一個函數,這些函數按照它們在數組中定義的順序被依次執行。
1、請求攔截器:
當Axios發起一個請求時,會首先遍歷并執行請求攔截器數組中的每個函數。
請求攔截器的作用是在請求發送前對請求進行修改或添加一些公共的邏輯,例如給每個請求體都加上token,或者修改請求的配置,如headers、url、params等。此外,也可以在此階段取消請求。
請求攔截器的修改或添加的配置將被用于之后的請求發送。
2、響應攔截器:
一旦請求被發送并得到響應,Axios會遍歷并執行響應攔截器數組中的每個函數。
響應攔截器的作用是在響應返回后對響應進行特定的處理,例如對返回的數據進行統一處理或對特定的錯誤進行處理。
如果響應是一個正常的響應,可以直接返回數據或對數據進行修改。如果響應是一個錯誤(例如,404或500狀態碼),可以進行錯誤處理或重試邏輯。
使用Axios攔截器的好處包括統一處理公共邏輯,減少重復代碼,提高代碼的可讀性和可維護性。同時,也可以在請求或響應不符合預期時進行統一處理,提高程序的健壯性。
需要注意的是,在使用Axios攔截器時,應確保請求攔截器在響應攔截器之前執行,避免邏輯上的錯誤。此外,應避免在攔截器中修改原始請求或響應數據,以免影響其他攔截器或請求處理器的處理結果。同時,應考慮性能問題,避免在攔截器中進行耗時的操作。
綜上所述,Axios攔截器的實現原理主要基于其內部維護的請求和響應攔截器數組,通過依次執行這些攔截器函數,實現對請求和響應的預處理和后處理。
二、Axios 源碼中,攔截器是怎么實現的?(最簡化的理解)
Axios 的攔截器實現基于 Axios 的核心原理,即 Axios 實例是一個包含請求和響應攔截器堆棧的對象。當發出請求或接收響應時,Axios 會遍歷這些攔截器,并按照添加的順序執行請求攔截器,以及按照相反的順序執行響應攔截器。
在 Axios 的源碼中,攔截器是通過一個 AxiosInterceptorManager
實例來管理的,它維護了一個攔截器數組。每個攔截器都是一個包含 fulfilled
和 rejected
函數的對象。這兩個函數分別對應于攔截器成功處理和攔截器處理出錯的情況。
以下是 Axios 攔截器管理器的一個簡化版本,展示了其核心實現思路:
class InterceptorManager {constructor() {this.handlers = []; // 存儲攔截器的數組}use(fulfilled, rejected) {this.handlers.push({fulfilled: fulfilled,rejected: rejected});return this.handlers.length - 1; // 返回攔截器的ID}eject(id) {if (this.handlers[id]) {this.handlers[id] = null; // 移除攔截器}}forEach(fn) {this.handlers.forEach((h) => {if (h !== null) {fn(h);}});}
}
在發送請求或接收響應時,Axios 會創建一個 promise
鏈,并通過 forEach
方法將攔截器中的 fulfilled
和 rejected
函數添加到這個鏈中。這樣,每個攔截器都可以對請求或響應進行處理,然后將結果傳遞到鏈的下一個攔截器,或者在出錯時結束鏈的執行。
PS:注意,上面說的是攔截管理器,并非下面要說的攔截器
axios.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {chain.unshift(interceptor.fulfilled, interceptor.rejected);
});axios.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {chain.push(interceptor.fulfilled, interceptor.rejected);
});
在 Axios 的完整實現中,這個攔截器機制被集成到了 Axios 的請求發送和響應處理流程中。通過這種方式,Axios 可以在發送請求之前和接收響應之后,但在用戶定義的 .then
或 .catch
執行之前,插入自定義的邏輯。
請注意,這里提供的代碼只是為了說明 Axios 攔截器的實現原理,并不是 Axios 源碼的完整復制。
三、高度簡化的源碼(axios攔截器實現源碼)
Axios 攔截器的實現源碼涉及到其核心模塊的設計。Axios 允許你注冊請求攔截器和響應攔截器,這些攔截器在請求發送前和響應返回后進行相應的處理。以下是簡化的 Axios 攔截器實現源碼的概述:
// 假設 Axios 實例有一個 interceptors 對象,其中包含了 request 和 response 兩個數組
const instance = {interceptors: {request: [],response: []}
};// 請求攔截器的函數定義
function onFulfilled(fulfilled, rejected) {return function (config) {return new Promise((resolve, reject) => {try {const result = fulfilled(config);if (result && typeof result.then === 'function') {result.then(resolvedConfig => {resolve(resolvedConfig);}, rejected);} else {resolve(result);}} catch (error) {reject(error);}};};
}// 響應攔截器的函數定義
function onFulfilledResponse(fulfilled, rejected) {return function (response) {return new Promise((resolve, reject) => {try {const result = fulfilled(response);if (result && typeof result.then === 'function') {result.then(resolvedResponse => {resolve(resolvedResponse);}, rejected);} else {resolve(result);}} catch (error) {reject(error);}};};
}// 添加請求攔截器
instance.interceptors.request.use = function (fulfilled, rejected) {this.interceptors.request.push({fulfilled: onFulfilled(fulfilled, rejected),rejected: rejected});return this;
};// 添加響應攔截器
instance.interceptors.response.use = function (fulfilled, rejected) {this.interceptors.response.push({fulfilled: onFulfilledResponse(fulfilled, rejected),rejected: rejected});return this;
};// 簡化版的請求發送函數,用于展示攔截器如何處理
function dispatchRequest(config) {return new Promise((resolve, reject) => {// 遍歷并執行請求攔截器const chain = [Promise.resolve(config)];instance.interceptors.request.forEach(interceptor => {chain.unshift(interceptor.fulfilled, interceptor.rejected);});// 遍歷并執行響應攔截器chain.push(dispatchRequestToServer); // 假設這個函數是實際發送請求到服務器的函數while (chain.length) {const currentInterceptor = chain.shift();const nextInterceptor = chain.shift();if (typeof currentInterceptor === 'function') {currentInterceptor(config).then(chain => {if (typeof nextInterceptor === 'function') {nextInterceptor(chain);} else {resolve(chain);}}).catch(reject);}}});
}// 假設函數,用于實際發送請求到服務器
function dispatchRequestToServer(config) {// 這里應該是實際的請求發送邏輯,為了簡化,我們直接返回一個模擬的響應return Promise.resolve({data: 'Response data'});
}// 使用攔截器
instance.interceptors.request.use(config => {// 在發送請求之前做些什么console.log('Request interceptor called', config);// 可以在這里修改config對象return config;},error => {// 對請求錯誤做些什么return Promise.reject(error);}
);instance.interceptors.response.use(response => {// 對響應數據做點什么console.log('Response interceptor called', response);// 可以在這里修改響應數據return response;},error => {// 對響應錯誤做點什么return Promise.reject(error);}
);// 發送請求
dispatchRequest({ url: 'https://api.example.com/data' }).then(response => {console.log('Response received:', response);}).catch(error => {console.error('Error occurred:', error);});
以上代碼是一個高度簡化的版本,用于展示 Axios 攔截器是如何實現的。如果你對 Axios 的攔截器實現細節感興趣,建議查看 Axios 的官方 GitHub 倉庫中的源碼。