這篇文章主要介紹“Axios核心原理是什么”,在日常操作中,相信很多人在Axios核心原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Axios核心原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
創(chuàng)新互聯(lián)公司長期為上1000+客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為社旗企業(yè)提供專業(yè)的網(wǎng)站建設、成都網(wǎng)站建設,社旗網(wǎng)站改版等技術服務。擁有10多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
一、axios簡介
axios是什么?
Axios 是一個基于 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。
axios有什么特性?(不得不說面試被問到幾次)
從瀏覽器中創(chuàng)建 XMLHttpRequests從 node.js
創(chuàng)建 http 請求
支持 Promise API
攔截請求和響應轉換請求數(shù)據(jù)和響應數(shù)據(jù)
取消請求
自動轉換JSON 數(shù)據(jù)
客戶端支持防御 XSRF
實際上,axios可以用在瀏覽器和 node.js 中是因為,它會自動判斷當前環(huán)境是什么,如果是瀏覽器,就會基于XMLHttpRequests實現(xiàn)axios。如果是node.js環(huán)境,就會基于node內置核心模塊http實現(xiàn)axios簡單來說,axios的基本原理就是
axios還是屬于 XMLHttpRequest, 因此需要實現(xiàn)一個ajax?;蛘呋趆ttp 。
還需要一個promise對象來對結果進行處理。
二、基本使用方式
axios基本使用方式主要有
axios(config)
axios.method(url, data , config)
// index.html文件 <html> <script type="text/javascript" src="./myaxios.js"></script> <body> <button class="btn">點我發(fā)送請求</button> <script> document.querySelector('.btn').onclick = function() { // 分別使用以下方法調用,查看myaxios的效果 axios.post('/postAxios', { name: '小美post' }).then(res => { console.log('postAxios 成功響應', res); }) axios({ method: 'post', url: '/getAxios' }).then(res => { console.log('getAxios 成功響應', res); }) } </script> </body> </html> </html>
三、實現(xiàn)axios和axios.method
從axios(config)的使用上可以看出導出的axios是一個方法。從axios.method(url, data , config)的使用可以看出導出的axios上或者原型上掛有get,post等方法。
實際上導出的axios就是一個Axios類中的一個方法。
如代碼所以,核心代碼是request。我們把request導出,就可以使用axios(config)這種形式來調用axios了。
class Axios { constructor() { } request(config) { return new Promise(resolve => { const {url = '', method = 'get', data = {}} = config; // 發(fā)送ajax請求 const xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onload = function() { console.log(xhr.responseText) resolve(xhr.responseText); } xhr.send(data); }) } }
怎么導出呢?十分簡單,new Axios,獲得axios實例,再獲得實例上的request方法就好了。
// 最終導出axios的方法,即實例的request方法 function CreateAxiosFn() { let axios = new Axios(); let req = axios.request.bind(axios); return req; }
// 得到最后的全局變量axios let axios = CreateAxiosFn();
點擊查看此時的myAxios.js
現(xiàn)在axios實際上就是request方法。
你可能會很疑惑,因為我當初看源碼的時候也很疑惑:干嘛不直接寫個request方法,然后導出呢?非得這樣繞這么大的彎子。別急。后面慢慢就會講到。
現(xiàn)在一個簡單的axios就完成了,我們來引入myAxios.js文件并測試一下可以使用不?
簡單的搭建服務器:
//server.js var express = require('express'); var app = express(); //設置允許跨域訪問該服務. app.all('*', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type'); res.header('Access-Control-Allow-Methods', '*'); res.header('Content-Type', 'application/json;charset=utf-8'); next(); }); app.get('/getTest', function(request, response){ data = { 'FrontEnd':'前端', 'Sunny':'陽光' }; response.json(data); }); var server = app.listen(5000, function(){ console.log("服務器啟動"); });
//index.html <script type="text/javascript" src="./myAxios.js"></script> <body> <button class="btn">點我發(fā)送請求</button> <script> document.querySelector('.btn').onclick = function() { // 分別使用以下方法調用,查看myaxios的效果 axios({ method: 'get', url: 'http://localhost:5000/getTest' }).then(res => { console.log('getAxios 成功響應', res); }) } </script> </body>
點擊按鈕,看看是否能成功獲得數(shù)據(jù)。
發(fā)現(xiàn)確實成功。
可喜可賀
現(xiàn)在我們來實現(xiàn)下axios.method()的形式。
思路:我們可以再Axios.prototype添加這些方法。而這些方法內部調用request方法即可,如代碼所示:
// 定義get,post...方法,掛在到Axios原型上 const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post']; methodsArr.forEach(met => { Axios.prototype[met] = function() { console.log('執(zhí)行'+met+'方法'); // 處理單個方法 if (['get', 'delete', 'head', 'options'].includes(met)) { // 2個參數(shù)(url[, config]) return this.request({ method: met, url: arguments[0], ...arguments[1] || {} }) } else { // 3個參數(shù)(url[,data[,config]]) return this.request({ method: met, url: arguments[0], data: arguments[1] || {}, ...arguments[2] || {} }) } } })
我們通過遍歷methodsArr數(shù)組,依次在Axios.prototype添加對應的方法,注意的是'get', 'delete', 'head', 'options'這些方法只接受兩個參數(shù)。而其他的可接受三個參數(shù),想一下也知道,get不把參數(shù)放body的。
但是,你有沒有發(fā)現(xiàn),我們只是在Axios的prototype上添加對應的方法,我們導出去的可是request方法啊,那怎么辦?簡單,把Axios.prototype上的方法搬運到request上即可。
我們先來實現(xiàn)一個工具方法,實現(xiàn)將b的方法混入a;
const utils = { extend(a,b, context) { for(let key in b) { if (b.hasOwnProperty(key)) { if (typeof b[key] === 'function') { a[key] = b[key].bind(context); } else { a[key] = b[key] } } } } }
然后我們就可以利用這個方法將Axios.prototype上的方法搬運到request上啦。
我們修改一下之前的CreateAxiosFn方法即可
function CreateAxiosFn() { let axios = new Axios(); let req = axios.request.bind(axios); 增加代碼 utils.extend(req, Axios.prototype, axios) return req; }
點擊查看此時的myAxios.js
現(xiàn)在來測試一下能不能使用axios.get()這種形式調用axios。
<body> <button class="btn">點我發(fā)送請求</button> <script> document.querySelector('.btn').onclick = function() { axios.get('http://localhost:5000/getTest') .then(res => { console.log('getAxios 成功響應', res); }) } </script> </body>
又是意料之中成功。再完成下一個功能之前,先給上目前myAxios.js的完整代碼
class Axios { constructor() { } request(config) { return new Promise(resolve => { const {url = '', method = 'get', data = {}} = config; // 發(fā)送ajax請求 console.log(config); const xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onload = function() { console.log(xhr.responseText) resolve(xhr.responseText); } xhr.send(data); }) } } // 定義get,post...方法,掛在到Axios原型上 const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post']; methodsArr.forEach(met => { Axios.prototype[met] = function() { console.log('執(zhí)行'+met+'方法'); // 處理單個方法 if (['get', 'delete', 'head', 'options'].includes(met)) { // 2個參數(shù)(url[, config]) return this.request({ method: met, url: arguments[0], ...arguments[1] || {} }) } else { // 3個參數(shù)(url[,data[,config]]) return this.request({ method: met, url: arguments[0], data: arguments[1] || {}, ...arguments[2] || {} }) } } }) // 工具方法,實現(xiàn)b的方法或屬性混入a; // 方法也要混入進去 const utils = { extend(a,b, context) { for(let key in b) { if (b.hasOwnProperty(key)) { if (typeof b[key] === 'function') { a[key] = b[key].bind(context); } else { a[key] = b[key] } } } } } // 最終導出axios的方法-》即實例的request方法 function CreateAxiosFn() { let axios = new Axios(); let req = axios.request.bind(axios); // 混入方法, 處理axios的request方法,使之擁有get,post...方法 utils.extend(req, Axios.prototype, axios) return req; } // 得到最后的全局變量axios let axios = CreateAxiosFn();
四、請求和響應攔截器
我們先看下攔截器的使用
// 添加請求攔截器 axios.interceptors.request.use(function (config) { // 在發(fā)送請求之前做些什么 return config; }, function (error) { // 對請求錯誤做些什么 return Promise.reject(error); }); // 添加響應攔截器 axios.interceptors.response.use(function (response) { // 對響應數(shù)據(jù)做點什么 return response; }, function (error) { // 對響應錯誤做點什么 return Promise.reject(error); });
攔截器是什么意思呢?其實就是在我們發(fā)送一個請求的時候會先執(zhí)行請求攔截器的代碼,然后再真正地執(zhí)行我們發(fā)送的請求,這個過程會對config,也就是我們發(fā)送請求時傳送的參數(shù)進行一些操作。
而當接收響應的時候,會先執(zhí)行響應攔截器的代碼,然后再把響應的數(shù)據(jù)返回來,這個過程會對response,也就是響應的數(shù)據(jù)進行一系列操作。
怎么實現(xiàn)呢?需要明確的是攔截器也是一個類,管理響應和請求。因此我們先實現(xiàn)攔截器
class InterceptorsManage { constructor() { this.handlers = []; } use(fullfield, rejected) { this.handlers.push({ fullfield, rejected }) } }
我們是用這個語句axios.interceptors.response.use和axios.interceptors.request.use,來觸發(fā)攔截器執(zhí)行use方法的。
說明axios上有一個響應攔截器和一個請求攔截器。那怎么實現(xiàn)Axios呢?看代碼
class Axios { constructor() { 新增代碼 this.interceptors = { request: new InterceptorsManage, response: new InterceptorsManage } } request(config) { return new Promise(resolve => { const {url = '', method = 'get', data = {}} = config; // 發(fā)送ajax請求 console.log(config); const xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onload = function() { console.log(xhr.responseText) resolve(xhr.responseText); }; xhr.send(data); }) } }
可見,axios實例上有一個對象interceptors。這個對象有兩個攔截器,一個用來處理請求,一個用來處理響應。
所以,我們執(zhí)行語句axios.interceptors.response.use和axios.interceptors.request.use的時候,實現(xiàn)獲取axios實例上的interceptors對象,然后再獲取response或request攔截器,再執(zhí)行對應的攔截器的use方法。
而執(zhí)行use方法,會把我們傳入的回調函數(shù)push到攔截器的handlers數(shù)組里。
到這里你有沒有發(fā)現(xiàn)一個問題。這個interceptors對象是Axios上的啊,我們導出的是request方法?。G?好熟悉的問題,上面提到過哈哈哈~~~額)。處理方法跟上面處理的方式一樣,都是把Axios上的方法和屬性搬到request過去,也就是遍歷Axios實例上的方法,得以將interceptors對象掛載到request上。
所以只要更改下CreateAxiosFn方法即可。
function CreateAxiosFn() { let axios = new Axios(); let req = axios.request.bind(axios); // 混入方法, 處理axios的request方法,使之擁有get,post...方法 utils.extend(req, Axios.prototype, axios) 新增代碼 utils.extend(req, axios) return req; }
好了,現(xiàn)在request也有了interceptors對象,那么什么時候拿interceptors對象中的handler之前保存的回調函數(shù)出來執(zhí)行。
沒錯,就是我們發(fā)送請求的時候,會先獲取request攔截器的handlers的方法來執(zhí)行。再執(zhí)行我們發(fā)送的請求,然后獲取response攔截器的handlers的方法來執(zhí)行。
因此,我們要修改之前所寫的request方法 之前是這樣的。
request(config) { return new Promise(resolve => { const {url = '', method = 'get', data = {}} = config; // 發(fā)送ajax請求 console.log(config); const xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onload = function() { console.log(xhr.responseText) resolve(xhr.responseText); }; xhr.send(data); }) }
但是現(xiàn)在request里不僅要執(zhí)行發(fā)送ajax請求,還要執(zhí)行攔截器handlers中的回調函數(shù)。所以,最好下就是將執(zhí)行ajax的請求封裝成一個方法
request(config) { this.sendAjax(config) } sendAjax(config){ return new Promise(resolve => { const {url = '', method = 'get', data = {}} = config; // 發(fā)送ajax請求 console.log(config); const xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onload = function() { console.log(xhr.responseText) resolve(xhr.responseText); }; xhr.send(data); }) }
好了,現(xiàn)在我們要獲得handlers中的回調
request(config) { // 攔截器和請求組裝隊列 let chain = [this.sendAjax.bind(this), undefined] // 成對出現(xiàn)的,失敗回調暫時不處理 // 請求攔截 this.interceptors.request.handlers.forEach(interceptor => { chain.unshift(interceptor.fullfield, interceptor.rejected) }) // 響應攔截 this.interceptors.response.handlers.forEach(interceptor => { chain.push(interceptor.fullfield, interceptor.rejected) }) // 執(zhí)行隊列,每次執(zhí)行一對,并給promise賦最新的值 let promise = Promise.resolve(config); while(chain.length > 0) { promise = promise.then(chain.shift(), chain.shift()) } return promise; }
我們先把sendAjax請求和undefined放進了chain數(shù)組里,再把請求攔截器的handlers的成對回調放到chain數(shù)組頭部。再把響應攔截器的handlers的承兌回調反倒chain數(shù)組的尾部。
然后再 逐漸取數(shù) chain數(shù)組的成對回調執(zhí)行。
promise = promise.then(chain.shift(), chain.shift())
這一句,實際上就是不斷將config從上一個promise傳遞到下一個promise,期間可能回調config做出一些修改。什么意思?我們結合一個例子來講解一下
首先攔截器是這樣使用的
// 添加請求攔截器 axios.interceptors.request.use(function (config) { // 在發(fā)送請求之前做些什么 return config; }, function (error) { // 對請求錯誤做些什么 return Promise.reject(error); }); // 添加響應攔截器 axios.interceptors.response.use(function (response) { // 對響應數(shù)據(jù)做點什么 return response; }, function (error) { // 對響應錯誤做點什么 return Promise.reject(error); });
然后執(zhí)行request的時候。chain數(shù)組的數(shù)據(jù)是這樣的
chain = [ function (config) { // 在發(fā)送請求之前做些什么 return config; }, function (error) { // 對請求錯誤做些什么 return Promise.reject(error); } this.sendAjax.bind(this), undefined, function (response) { // 對響應數(shù)據(jù)做點什么 return response; }, function (error) { // 對響應錯誤做點什么 return Promise.reject(error); } ]
首先
執(zhí)行第一次promise.then(chain.shift(), chain.shift()),即
promise.then( function (config) { // 在發(fā)送請求之前做些什么 return config; }, function (error) { // 對請求錯誤做些什么 return Promise.reject(error); } )
一般情況,promise是resolved狀態(tài),是執(zhí)行成功回調的,也就是執(zhí)行
function (config) { // 在發(fā)送請求之前做些什么 return config; },
promise.then是要返回一個新的promise對象的。為了區(qū)分,在這里,我會把這個新的promise對象叫做第一個新的promise對象 這個第一個新的promise對象會把
function (config) { // 在發(fā)送請求之前做些什么 return config; },
的執(zhí)行結果傳入resolve函數(shù)中
resolve(config)
使得這個返回的第一個新的promise對象的狀態(tài)為resovled,而且第一個新的promise對象的data為config。
這里需要對Promise的原理足夠理解。所以我前一篇文章寫的是手寫Promise核心原理,再也不怕面試官問我Promise原理,你可以去看看
接下來,再執(zhí)行
promise.then( sendAjax(config) , undefined )
注意:這里的promise是 上面提到的第一個新的promise對象。
而promise.then這個的執(zhí)行又會返回第二個新的promise對象。
因為這里promise.then中的promise也就是第一個新的promise對象的狀態(tài)是resolved的,所以會執(zhí)行sendAjax()。而且會取出第一個新的promise對象的data 作為config轉入sendAjax()。
當sendAjax執(zhí)行完,就會返回一個response。這個response就會保存在第二個新的promise對象的data中。
接下來,再執(zhí)行
promise.then( function (response) { // 對響應數(shù)據(jù)做點什么 return response; }, function (error) { // 對響應錯誤做點什么 return Promise.reject(error); } )
同樣,會把第二個新的promise對象的data取出來作為response參數(shù)傳入
function (response) { // 對響應數(shù)據(jù)做點什么 return response; },
飯后返回一個promise對象,這個promise對象的data保存了這個函數(shù)的執(zhí)行結果,也就是返回值response。
然后通過return promise;
把這個promise返回了。咦?是怎么取出promise的data的。我們看看我們平常事怎么獲得響應數(shù)據(jù)的
axios.get('http://localhost:5000/getTest') .then(res => { console.log('getAxios 成功響應', res); })
在then里接收響應數(shù)據(jù)。所以原理跟上面一樣,將返回的promise的data作為res參數(shù)了。
現(xiàn)在看看我們的myAxios完整代碼吧,好有個全面的了解
class InterceptorsManage { constructor() { this.handlers = []; } use(fullfield, rejected) { this.handlers.push({ fullfield, rejected }) } } class Axios { constructor() { this.interceptors = { request: new InterceptorsManage, response: new InterceptorsManage } } request(config) { // 攔截器和請求組裝隊列 let chain = [this.sendAjax.bind(this), undefined] // 成對出現(xiàn)的,失敗回調暫時不處理 // 請求攔截 this.interceptors.request.handlers.forEach(interceptor => { chain.unshift(interceptor.fullfield, interceptor.rejected) }) // 響應攔截 this.interceptors.response.handlers.forEach(interceptor => { chain.push(interceptor.fullfield, interceptor.rejected) }) // 執(zhí)行隊列,每次執(zhí)行一對,并給promise賦最新的值 let promise = Promise.resolve(config); while(chain.length > 0) { promise = promise.then(chain.shift(), chain.shift()) } return promise; } sendAjax(){ return new Promise(resolve => { const {url = '', method = 'get', data = {}} = config; // 發(fā)送ajax請求 console.log(config); const xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onload = function() { console.log(xhr.responseText) resolve(xhr.responseText); }; xhr.send(data); }) } } // 定義get,post...方法,掛在到Axios原型上 const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post']; methodsArr.forEach(met => { Axios.prototype[met] = function() { console.log('執(zhí)行'+met+'方法'); // 處理單個方法 if (['get', 'delete', 'head', 'options'].includes(met)) { // 2個參數(shù)(url[, config]) return this.request({ method: met, url: arguments[0], ...arguments[1] || {} }) } else { // 3個參數(shù)(url[,data[,config]]) return this.request({ method: met, url: arguments[0], data: arguments[1] || {}, ...arguments[2] || {} }) } } }) // 工具方法,實現(xiàn)b的方法混入a; // 方法也要混入進去 const utils = { extend(a,b, context) { for(let key in b) { if (b.hasOwnProperty(key)) { if (typeof b[key] === 'function') { a[key] = b[key].bind(context); } else { a[key] = b[key] } } } } } // 最終導出axios的方法-》即實例的request方法 function CreateAxiosFn() { let axios = new Axios(); let req = axios.request.bind(axios); // 混入方法, 處理axios的request方法,使之擁有get,post...方法 utils.extend(req, Axios.prototype, axios) return req; } // 得到最后的全局變量axios let axios = CreateAxiosFn();
來測試下攔截器功能是否正常
<script type="text/javascript" src="./myAxios.js"></script> <body> <button class="btn">點我發(fā)送請求</button> <script> // 添加請求攔截器 axios.interceptors.request.use(function (config) { // 在發(fā)送請求之前做些什么 config.method = "get"; console.log("被我請求攔截器攔截了,哈哈:",config); return config; }, function (error) { // 對請求錯誤做些什么 return Promise.reject(error); }); // 添加響應攔截器 axios.interceptors.response.use(function (response) { // 對響應數(shù)據(jù)做點什么 console.log("被我響應攔截攔截了,哈哈 "); response = {message:"響應數(shù)據(jù)被我替換了,啊哈哈哈"} return response; }, function (error) { // 對響應錯誤做點什么 console.log("錯了嗎"); return Promise.reject(error); }); document.querySelector('.btn').onclick = function() { // 分別使用以下方法調用,查看myaxios的效果 axios({ url: 'http://localhost:5000/getTest' }).then(res => { console.log('response', res); }) } </script> </body>
攔截成功?。。。?!
到此,關于“Axios核心原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
網(wǎng)頁標題:Axios核心原理是什么
標題網(wǎng)址:http://jinyejixie.com/article6/ijjsog.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供建站公司、服務器托管、用戶體驗、定制網(wǎng)站、自適應網(wǎng)站、企業(yè)網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)