Axios 的簡單概述以及它的一個核心功能攔截器的詳解
一、概述
Axios 是一個基於 Promise 的 HTTP 客戶端,可以用在瀏覽器和 node.js 中,本質是XMLHttpRequests請求即ajax請求。
擁有以下特性:
從瀏覽器中建立 XMLHttpRequests
從 node.js 建立 http 請求
支援Promise API;
能夠攔截請求和響應;
能夠轉換請求和響應資料;
能夠取消請求;
能夠自定轉化JSON資料;
客戶端支援防禦CSRF(XSRF)
Axios 支援大多數主流的瀏覽器,比如 Chrome、Firefox、Safari 和 IE 8以上。
詳細可訪問axios中文網::http://www.axios-js.com/zh-cn/docs/
二、HTTP 攔截器的設計與實現
2.1 需求分析
比如通常會使用 token 進行使用者的身份認證。這就要求在認證通過後,我們需要在每個請求上都攜帶認證資訊。針對這個需求,為了避免為每個請求單獨處理,所以一般通過封裝統一的 request
函式來為每個請求統一新增 token 資訊。
但是如果響應進行統一處理的話,會越來越難維護,所以希望在接收到響應之後做一些額外的邏輯
因此,Axios 為我們提供瞭解決方案 —— 攔截器,作用如下:
請求攔截器:該類攔截器的作用是在請求傳送前統一執行某些操作,比如在請求頭中新增 token 欄位。
響應攔截器:該類攔截器的作用是在接收到伺服器響應後統一執行某些操作,比如發現響應狀態碼為 401 時,自動跳轉到登入頁。
攔截器的使用方式如下:
在 axios
物件上有一個 interceptors
物件屬性,該屬性又有 request
和 response
2 個屬性, axios.interceptors.request
和 axios.interceptors.response
物件提供了 use
方法,就可以分別設定請求攔截器和響應攔截器:(use
方法支援 2 個引數,第一個引數類似 Promise 的 resolve
函式,第二個引數類似 Promise 的 reject
函式。我們可以在 resolve
函式和 reject
函式中執行同步程式碼或者是非同步程式碼邏輯。)
// 新增一個請求攔截器
axios.interceptors.request.use(function (config){
// 在傳送請求之前可以做一些事情
config.headers.token = 'added by interceptor'; //在headers中攜帶token
return config;
},function (error){
// 處理請求錯誤
return Promise.reject(error)
});
// 新增一個響應攔截器
axios.interceptors.response.use(function (res){
// 在傳送請求之前可以做一些事情
return res;
},function (error){
// 處理請求錯誤
return Promise.reject(error)
});
我們先來分析一下攔截器的設計思路。Axios 的作用是用於傳送 HTTP 請求,而請求攔截器和響應攔截器的本質都是一個實現特定功能的函式。
我們可以按照功能把傳送 HTTP 請求拆解成不同型別的子任務,比如有用於處理請求配置物件的子任務,用於傳送 HTTP 請求的子任務和用於處理響應物件的子任務。當我們按照指定的順序來執行這些子任務時,就可以完成一次完整的 HTTP 請求。
瞭解完這些,接下來我們將從 任務註冊、任務編排和任務排程 三個方面來分析 Axios 攔截器的實現。
2.2 任務註冊
通過前面攔截器的使用示例,我們已經知道如何註冊請求攔截器和響應攔截器,其中請求攔截器用於處理請求配置物件的子任務,而響應攔截器用於處理響應物件的子任務。要搞清楚任務是如何註冊的,就需要了解 axios
和 axios.interceptors
物件。
// lib/axios.js
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
在 Axios 的原始碼中,我們找到了 axios
物件的定義,很明顯預設的 axios
例項是通過 createInstance
方法建立的,該方法最終返回的是 Axios.prototype.request
函式物件。同時,我們發現了 Axios
的建構函式:
// lib/core/Axios.js
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
在建構函式中,我們找到了 axios.interceptors
物件的定義,也知道了 interceptors.request
和 interceptors.response
物件都是 InterceptorManager
類的例項。因此接下來,進一步分析 InterceptorManager
建構函式及相關的 use
方法就可以知道任務是如何註冊的:
// lib/core/InterceptorManager.js
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
// 返回當前的索引,用於移除已註冊的攔截器
return this.handlers.length - 1;
};
通過觀察 use
方法,我們可知註冊的攔截器都會被儲存到 InterceptorManager
物件的 handlers
屬性中。下面我們用一張圖來總結一下 Axios
物件與 InterceptorManager
物件的內部結構與關係:
2.3 任務編排
現在我們已經知道如何註冊攔截器任務,但僅僅註冊任務是不夠,我們還需要對已註冊的任務進行編排,這樣才能確保任務的執行順序。這裡我們把完成一次完整的 HTTP 請求分為處理請求配置物件、發起 HTTP 請求和處理響應物件 3 個階段。
接下來我們來看一下 Axios 如何發請求的:
axios({
url: '/hello',
method: 'get',
}).then(res =>{
console.log('axios res: ', res)
console.log('axios res.data: ', res.data)
})
通過前面的分析,我們已經知道 axios
物件對應的是 Axios.prototype.request
函式物件,該函式的具體實現如下:
// lib/core/Axios.js
Axios.prototype.request = function request(config) {
config = mergeConfig(this.defaults, config);
// 省略部分程式碼
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
// 任務編排
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
// 任務排程
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
任務編排的程式碼比較簡單,我們來看一下任務編排前和任務編排後的對比圖:
2.4 任務排程
任務編排完成後,要發起 HTTP 請求,我們還需要按編排後的順序執行任務排程。在 Axios 中具體的排程方式很簡單,具體如下所示:
// lib/core/Axios.js
Axios.prototype.request = function request(config) {
// 省略部分程式碼
var promise = Promise.resolve(config);
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
}
因為 chain 是陣列,所以通過 while 語句我們就可以不斷地取出設定的任務,然後組裝成 Promise 呼叫鏈從而實現任務排程,對應的處理流程如下圖所示:
下面我們來回顧一下 Axios 攔截器完整的使用流程:
// 新增請求攔截器 —— 處理請求配置物件
axios.interceptors.request.use(function (config) {
config.headers.token = 'added by interceptor';
return config;
});
// 新增響應攔截器 —— 處理響應物件
axios.interceptors.response.use(function (data) {
data.data = data.data + ' - modified by interceptor';
return data;
});
axios({
url: '/hello',
method: 'get',
}).then(res =>{
console.log('axios res.data: ', res.data)
})
介紹完 Axios 的攔截器,我們來總結一下它的優點。Axios 通過提供攔截器機制,讓開發者可以很容易在請求的生命週期中自定義不同的處理邏輯。此外,也可以通過攔截器機制來靈活地擴充套件 Axios 的功能,比如 Axios 生態中列舉的 axios-response-logger 和 axios-debug-log 這兩個庫。
參考 Axios 攔截器的設計模型,我們就可以抽出以下通用的任務處理模型:
相關文章
- spring攔截器的一個簡單例子Spring單例
- 基於原生fetch封裝一個帶有攔截器功能的fetch,類似axios的攔截器封裝iOS
- axios攔截器iOS
- axios 攔截器iOS
- axios 攔截器 的使用方法iOS
- 聊聊如何實現一個帶有攔截器功能的SPI
- vue中用axios攔截器攔截請求和響應VueiOS
- Spring 常用的三種攔截器詳解Spring
- axios原始碼分析——攔截器iOS原始碼
- Struts2中攔截器的簡單實現
- 【axios】XHR的ajax封裝+axios攔截器呼叫+請求取消iOS封裝
- axios的全域性攔截之axios.interceptorsiOS
- struts的常用配置以及自定義攔截器
- 短視訊直播系統,軟體自帶的攔截器,攔截功能
- Spring MVC 中的攔截器的使用“攔截器基本配置” 和 “攔截器高階配置”SpringMVC
- ES6 Proxy攔截器詳解
- 一比一還原axios原始碼(五)—— 攔截器iOS原始碼
- Struts2教程8:攔截器概述
- Mybatis中的攔截器MyBatis
- SpringMVC攔截器,設定不攔截的URLSpringMVC
- Axios、axios攔截器、fetch-jsonp ——0807iOSJSON
- OkHttp 原始碼剖析系列(一)——請求的發起及攔截器機制概述HTTP原始碼
- OkHttp 攔截器的一些騷操作HTTP
- 攔截器,攔截器棧總結
- webwork的攔截器真是好用Web
- Java實現的攔截器Java
- grpc中的攔截器RPC
- SpringMVC中的攔截器SpringMVC
- 前端架構之vue+axios 前端實現登入攔截(路由攔截、http攔截)前端架構VueiOS路由HTTP
- React、Axios、MockJs實現Ajax的請求攔截ReactiOSMockJS
- Koa的洋蔥中介軟體,Redux的中介軟體,Axios的攔截器讓你迷惑嗎?實現一個精簡版的就徹底搞懂了。ReduxiOS
- 來瞧一瞧 gRPC的攔截器RPC
- spring mvc攔截器,spring攔截器以及AOP切面的區別和原始碼SpringMVC原始碼
- SpringBoot自定義攔截器實現IP白名單功能Spring Boot
- spring mvc 攔截器的使用SpringMVC
- Struts2 ---攔截器的理解
- 自定義攔截器,攔截到了某個請求就返回給前端一個JSON串前端JSON
- 關於axios以及jsonp的簡單使用方法iOSJSON