axios對外出口API的設計方法
本文我們將討論 axios 對外出口 API 是如何設計的。
axios 的 2 種使用方式
當通過 npm install axios
安裝完 axios 之后,就可以以下 2 種方式使用 axios。
一種是在請求時傳入 axios 配置項。
// GET 請求 axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }) .finally(function () { // always executed }); // POST 請求 axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
還有一種,就是通過 axios.create() 創(chuàng)建一個包含預配置的 axios,再進行請求。
const instance = axios.create({ baseURL: 'https://some-domain.com/api/', timeout: 1000, headers: {'X-Custom-Header': 'foobar'} }); axios.get('/user') axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'})
這樣就避免了每個請求中總是重復書寫相同配置的苦惱。
請求方法別名
在實際項目中使用 axios 請求時,我們通過會使用 axios.method() 的方式發(fā)送請求。這樣的方法一共有 8 個:
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.options(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
- axios(config)
這 8 個請求方法,底層都是基于 axios.request(config) 封裝的。
其中:
- axios(config) 是 axios.request(config) 的別名
- axios.get、axios.delete、axios.head、axios.options(url[, config]) 類似于 axios.request({ ...config, method, url, data: config?.data })
- axios.post、axios.put、axios.patch(url[, data[, config]]) 類似于 axios.request({ ...config, method, url, data })
了解了這些請求方法別名后,我們就來看它們的底層實現(xiàn)。
Axios 類
axios 其實是內部 Axios 類的實例。Axios 類的源碼位于 lib/core/Axios.js。
其總體實現(xiàn)如下:
// /v1.6.8/lib/core/Axios.js class Axios { // 1) constructor(instanceConfig) { this.defaults = instanceConfig; this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager() }; } // 2) async request(configOrUrl, config) {/* ... */} // 3) getUri(config) {/* ... */} } // 3) ['delete', 'get', 'head', 'options'].forEach(function forEachMethodNoData(method) {/* ... */}) ['post', 'put', 'patch'].forEach(function forEachMethodNoData(method) {/* ... */})
1):可以看到,Axios 類的實現(xiàn)代碼還是比較少的,就 2 個方法:
async request()
就對應前面所說的 axios.request(),是所有請求的入口地方getUri()
比較少用,是用來獲得完整請求路徑(基于當前 axios 的默認配置和你傳入的配置)
2):另外,在創(chuàng)建 Axios 實例時,實例對象上會綁定 defaults、interceptors 屬性。
- defaults 是在創(chuàng)建 Axios 實例傳入的配置,作為默認配置用
- interceptors 則是攔截器配置入口,如果你設置過攔截器,肯定知道它
3):最后這部分的代碼,其實就是基于 Axios.prototype.request 方法進行封裝,分別在 Axios.prototype 上添加 'delete'、'get'、'head'、'options' 和 'post'、'put'、'patch' 方法,前 4 個是一類,后 3 個是一類。
接下來,我們詳細說一下。
Axios.prototype.request()
這是 axios 實現(xiàn)核心請求邏輯的方法。
為了避免贅述,我這里給出偽代碼實現(xiàn)。
async request(configOrUrl, config) { // 獲得傳入的配置 config = getFinalConfigBy(configOrUrl, config) // 與內部默認配置合并 config = mergeConfig(this.defaults, config); // 拼裝完整請求鏈 const chain = [] .concat(requestInterceptorChain) .concat(dispatchRequest) .concat(responseInterceptorChain) // 發(fā)起并返回請求結果 return request(chain) }
axios.defaults/interceptors
這是 Axios 實例上的兩個屬性。
axios.defaults 允許你做默認配置的修改,會對所有當前 axios 實例的請求都生效。
axios.interceptors 則用來提供配置請求/響應攔截器。interceptors.request 允許你在請求前修改請求配置,interceptors.response 則允許你在請求得到響應后、交由用戶處理前,提前統(tǒng)一對響應數(shù)據(jù)做處理。
request、response 2 個屬性都是 InterceptorManager 實例,提供 use()
/eject()
/clear()
(對外) 方法和 forEach()
(對內)方法。
有興趣的想要了解攔截器實現(xiàn)機制的讀者,可以瀏覽之前的《axios 攔截器機制是如何實現(xiàn)的?》 一文進行學習。
請求方法別名
再來看看請求方法別名的實現(xiàn)。
先看 'delete'、'get'、'head'、'options' 這 4 個方法。
// /v1.6.8/lib/core/Axios.js#L193-L202 ['delete', 'get', 'head', 'options'].forEach(function forEachMethodNoData(method) { Axios.prototype[method] = function(url, config) { return this.request(mergeConfig(config || {}, { method, url, data: (config || {}).data })); }; });
實現(xiàn)稍稍簡單。本質上就是為 Axios.prototype 分別添加以上述 4 種請求方式為名的請求實現(xiàn)。this.request() 就是 Axios.prototype.request() 方法。
以 axios.delete(url, config) 為例:'delete' 作為 config.method,url 作為 config.url,最后和傳入的 config 合并成一個,交由 axios.request() 處理。
再來看看 'post'、'put'、'patch' 這 3 個方法的實現(xiàn)。
// /v1.6.8/lib/core/Axios.js#L204-L223 ['post', 'put', 'patch'].forEach(function forEachMethodWithData(method) { function generateHTTPMethod(isForm) { return function httpMethod(url, data, config) { return this.request(mergeConfig(config || {}, { method, headers: isForm ? { 'Content-Type': 'multipart/form-data' } : {}, url, data })); }; } Axios.prototype[method] = generateHTTPMethod(); Axios.prototype[method + 'Form'] = generateHTTPMethod(true); });
會稍稍復雜一丟丟。因為 axios 還額外支持了 'postForm'、'putForm'、'patchForm' 3 個方法,用于傳輸文件的場景。
以 axios.post(url, data, config) 為例:'post' 作為 config.method,url 作為 config.url,data 作為 config.data,最后和傳入的 config 合并成一個,交由 axios.request() 處理。
以 axios.postForm(url, data, config) 為例,相比 axios.post(url, data, config),多傳入了一個 'Content-Type': 'multipart/form-data' 的請求頭配置。這個請求頭項會幫助后端理解要處理的請求類型。
導出 axios
以上我們介紹了 Axios 類的邏輯實現(xiàn)。
如果直接導出 Axios
不過,如果只導出 Axios 類作為對外輸出,那么使用方式就是下面這樣。
////// // axios.js ////// export { default as defaults } from './defaults/index.js'; export default Axios; ////// // app.js ////// import Axios, { defaults } from 'axios' // 使用方式一 new Axios(defaults).get('/user') new Axios(defaults).post('/user', {firstName: 'Fred',lastName: 'Flintstone'}) // 使用方式二 const createAxios = () { return new Axios(defaults) } const axios = createAxios() axios.get('/user') axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'})
new Axios() 創(chuàng)建實例的方式不夠優(yōu)雅,而且每次使用都會有一段樣板代碼。
為了減少這部分的工作,axios 團隊在導出時針對 Axios 做了一層封裝,讓導出 API 更加好用。源碼位于 lib/axios.js。
// /v1.6.8/lib/axios.js#L28-L44 function createInstance(defaultConfig) { // 1.1) const context = new Axios(defaultConfig); const instance = Axios.prototype.request.bind(context); // 2) // Copy axios.prototype to instance utils.extend(instance, Axios.prototype, context, {allOwnKeys: true}); // Copy context to instance utils.extend(instance, context, null, {allOwnKeys: true}); // 3) // Factory for creating new instances instance.create = function create(instanceConfig) { return createInstance(mergeConfig(defaultConfig, instanceConfig)); }; // 1.2) return instance; } // 1) // Create the default instance to be exported const axios = createInstance(defaults); // this module should only have a default export export default axios
1)、首先,導出的 axios 其實是 createInstance(defaults) 的返回值
參數(shù) defaults 是 axios 內部默認配置信息。
import defaults from './defaults/index.js';
而 createInstance() 內部,返回的其實并不是 Axios 實例,而是 Axios 實例的 request() 方法。
function createInstance(defaultConfig) { // 返回的并不是 Axios 實例 const context = new Axios(defaultConfig); // 而是 Axios 實例的 request() 方法 const instance = Axios.prototype.request.bind(context); // ... return instance; }
這樣,我們就能以 axios(config) 方式發(fā)起請求,沒必要寫成 axios.request(config) 這樣了。
同時值得注意的時,request() 方法內部的 this 綁定到了 Axios 實例(即 context)上。這樣,request() 方法內部訪問的 this 時就不會有問題了。
2)、不過 instance(也就是 axios.request)上現(xiàn)在是沒有 Axios 實例上的其他方法了!
因此,接下來我們把 Axios.prototype 和 context 上的屬性都復制給 instance。
function createInstance(defaultConfig) { const context = new Axios(defaultConfig); const instance = Axios.prototype.request.bind(context); // 把 Axios.prototype 上的屬性都復制給 instance utils.extend(instance, Axios.prototype, context, {allOwnKeys: true}); // 把 context 上的屬性都復制給 instance utils.extend(instance, context, null, {allOwnKeys: true}); // ... return instance; }
如此一來,我們就能在 instance 上調用 get()/post()/getUri() 等這些方法了。
3)另外,在來實現(xiàn) axios.create()
function createInstance(defaultConfig) { // ... // 基于內部默認配置,在創(chuàng)建一個新的 Axios 實例 instance.create = function create(instanceConfig) { return createInstance(mergeConfig(defaultConfig, instanceConfig)); }; return instance; }
可以看到 instance.create 手動增加了 create() 方法。
create() 方法內部其實就是遞歸調用 createInstance()。不同的是,instance.create() 本質上是基于導出的 axios 的基礎上再多一步自定義配置合并。
總結
本文我們講解了 axios 對外出口 API 是如何設計的。
我們首先介紹了內部 Axios 類的實現(xiàn),這是 axios 核心邏輯所在;其次為了讓出口 API 更好使用,真正導出的 axios 其實是 Axios 實例的 request() 方法,最后又在增加了 create() 方法,方便進一步得到擁有自定義配置的 axios 對象。
以上就是axios對外出口API的設計方法的詳細內容,更多關于axios對外出口API的資料請關注腳本之家其它相關文章!
相關文章
BootStrap實現(xiàn)帶有增刪改查功能的表格(DEMO詳解)
這篇文章主要介紹了BootStrap實現(xiàn)帶有增刪改查功能的表格,表格封裝了3個版本,接下來通過本文給大家展示下樣式及代碼,對bootstrap增刪改查相關知識感興趣的朋友一起通過本文學習吧2016-10-10利用JS如何計算字符串所占字節(jié)數(shù)示例代碼
因為最近項目有個需求要用js計算一串字符串寫入到localStorage里所占的內存,所以便有了這篇文章,下面這篇文章主要給大家介紹了關于利用JS如何計算字符串所占字節(jié)數(shù)的相關資料,需要的朋友可以參考下。2017-09-09JS獲取子節(jié)點、父節(jié)點和兄弟節(jié)點的方法實例總結
這篇文章主要介紹了JS獲取子節(jié)點、父節(jié)點和兄弟節(jié)點的方法,結合實例形式總結分析了JavaScript針對子節(jié)點、父節(jié)點和兄弟節(jié)點獲取相關操作技巧與使用注意事項,需要的朋友可以參考下2018-07-07document.all還是document.getElementsByName?
document.all還是document.getElementsByName?...2006-07-07