axios的interceptors多次執(zhí)行問(wèn)題解決
問(wèn)題
在進(jìn)行 axios
封裝的時(shí)候,遇到個(gè)問(wèn)題,就是每次發(fā)起請(qǐng)求時(shí)axios 都會(huì)執(zhí)行兩次響應(yīng)攔截,甚是納悶,一時(shí)理不出思路來(lái)。
代碼如下:
class Http { constructor(config) { this.axios = axios; this.axiosInterceptor = undefined; // 公共的 header let defaultHeaders = { 'Content-Type': 'application/json;charset=UTF-8', 'Accept': 'application/json', // 通過(guò)頭指定,獲取的數(shù)據(jù)類型是JSON 'application/json, text/plain, */*', 'x-end-point': '.10.' } if(config?.headers){ for (let i in config.headers) { defaultHeaders[i] = config.headers[i]; } } axios({ // `baseURL` 將自動(dòng)加在 `url` 前面,除非 `url` 是一個(gè)絕對(duì) URL。 // 它可以通過(guò)設(shè)置一個(gè) `baseURL` 便于為 axios 實(shí)例的方法傳遞相對(duì) URL baseURL: config?.baseURL, // `url` 是用于請(qǐng)求的服務(wù)器 URL url: config?.url, // `method` 是創(chuàng)建請(qǐng)求時(shí)使用的方法 method: config?.method || 'get', // `headers` 是即將被發(fā)送的自定義請(qǐng)求頭 headers: {...defaultHeaders}, // `params` 是即將與請(qǐng)求一起發(fā)送的 URL 參數(shù) // 必須是一個(gè)無(wú)格式對(duì)象(plain object)或 URLSearchParams 對(duì)象 params: config?.method === 'get' ? config?.params || {} : {}, // `paramsSerializer` 是一個(gè)負(fù)責(zé) `params` 序列化的函數(shù) // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) paramsSerializer: function(params) { return Qs.stringify(params, {arrayFormat: 'brackets'}) }, // `data` 是作為請(qǐng)求主體被發(fā)送的數(shù)據(jù) // 只適用于這些請(qǐng)求方法 'PUT', 'POST', 和 'PATCH' // 在沒(méi)有設(shè)置 `transformRequest` 時(shí),必須是以下類型之一: // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams // - 瀏覽器專屬:FormData, File, Blob // - Node 專屬: Stream data: config?.method === 'post' ? config?.params || {} : {}, // `timeout` 指定請(qǐng)求超時(shí)的毫秒數(shù)(0 表示無(wú)超時(shí)時(shí)間) // 如果請(qǐng)求話費(fèi)了超過(guò) `timeout` 的時(shí)間,請(qǐng)求將被中斷 timeout: 0, // `withCredentials` 表示跨域請(qǐng)求時(shí)是否需要使用憑證 withCredentials: false, // default 為true則產(chǎn)生跨域,跨域攜帶cookie // `responseType` 表示服務(wù)器響應(yīng)的數(shù)據(jù)類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' responseType: 'json', // default }); // 添加請(qǐng)求攔截器 axios.interceptors.request.use( (config) => { // 在發(fā)送請(qǐng)求之前做些什么 return config; }, function (error) { // 對(duì)請(qǐng)求錯(cuò)誤做些什么 return Promise.reject(error); }); // 添加響應(yīng)攔截器 axios.interceptors.response.use((res) => { const { status, data } = res; // 對(duì)錯(cuò)誤狀態(tài)提示進(jìn)行處理 let message = '' if (status < 200 || status >= 300) { // 處理http錯(cuò)誤,拋到業(yè)務(wù)代碼 message = this.showResState(status) if (typeof res.data === 'string') { res.data = {code:status, message } } else { res.data.code = status res.data.message = message } } return res.data; }, function (error) { // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么 return Promise.reject(error); }); } get(url,params={}){ // 為給定 ID 的 user 創(chuàng)建請(qǐng)求 return new Promise((resolve, reject) => { this.axios.get(url,{ params }).then(response => { // 2. 如果成功了, 調(diào)用resolve(value) resolve(response); }) .catch(error => { // 3. 如果失敗了, 不調(diào)用reject(reason), 而是提示異常信息 reject(error) // message.error('請(qǐng)求出錯(cuò)了: ' + error.message).then(r => {}); }).finally(() => { }) }); } post(url,params={}){ return new Promise((resolve, reject) => { this.axios.post(url, params).then(response => { // 2. 如果成功了, 調(diào)用resolve(value) resolve(response); }) .catch(error => { // 3. 如果失敗了, 不調(diào)用reject(reason), 而是提示異常信息 reject(error) // message.error('請(qǐng)求出錯(cuò)了: ' + error.message).then(r => {}); }).finally(() => { }) }); } showResState (state) { let message = ''; // 這里只做部分常見(jiàn)的示例,具體根據(jù)需要進(jìn)行配置 switch (state) { case 400: message = '請(qǐng)求錯(cuò)誤(400)' break case 401: message = '未授權(quán),請(qǐng)重新登錄(401)' break case 403: message = '拒絕訪問(wèn)(403)' break case 404: message = '請(qǐng)求出錯(cuò)(404)' break case 500: message = '服務(wù)器錯(cuò)誤(500)' break case 501: message = '服務(wù)未實(shí)現(xiàn)(501)' break case 502: message = '網(wǎng)絡(luò)錯(cuò)誤(502)' break case 503: message = '服務(wù)不可用(503)' break default: message = `連接出錯(cuò)(${state})!` } return `${message},請(qǐng)檢查網(wǎng)絡(luò)或聯(lián)系網(wǎng)站管理員!` } // 插件初始化時(shí)會(huì)傳入所需的配置項(xiàng) autoAddToken (config) { // 在請(qǐng)求階段時(shí)修改 config 配置項(xiàng)為其添加 token 具體屬性名稱可自定義 config.headers ??= {} config.headers.Authorization = localStorage.token || null return config } } export default Http;
可能遇到過(guò)該類問(wèn)題的小伙伴們一眼就看出問(wèn)題所在,對(duì)于未有碰到過(guò)這個(gè)問(wèn)題的小伙伴,可能就又點(diǎn)煎熬了。
原因
若你使用use,就像Node.js里的use那樣,會(huì)不斷地往axios對(duì)象添加interceptors,由于我將該攔截器放在函數(shù)內(nèi),只要函數(shù)被執(zhí)行,則會(huì)再次將攔截器函數(shù)增添到axios對(duì)象上。
所以,推薦的辦法是,將攔截器放在函數(shù)外,可我的需求決定了,我必須將它放在函數(shù)內(nèi),那么該如何解決呢?
解決
添加該文件內(nèi)的唯一變量標(biāo)識(shí)符let interceptor = null,進(jìn)行判斷,只要攔截器存在,則不會(huì)繼續(xù)添加,部分代碼如下所示:
if (!this.interceptor) { // 添加響應(yīng)攔截器 this.interceptor = axios.interceptors.response.use((res) => { const { status, data } = res; // 對(duì)錯(cuò)誤狀態(tài)提示進(jìn)行處理 let message = '' if (status < 200 || status >= 300) { // 處理http錯(cuò)誤,拋到業(yè)務(wù)代碼 message = this.showResState(status) if (typeof res.data === 'string') { res.data = {code:status, message } } else { res.data.code = status res.data.message = message } } return res.data; }, function (error) { // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么 return Promise.reject(error); }); }
奈何不好使。不得一不得不把攔截器提取到類外部,問(wèn)題解決。
這里只貼部分主要代碼:
import axios from "axios"; /* 將攔截器 置于封裝類之外 */ // 添加請(qǐng)求攔截器 axios.interceptors.request.use( (config) => { // 在發(fā)送請(qǐng)求之前做些什么 添加 token 等鑒權(quán)功能 //... return config; }, function (error) { // 對(duì)請(qǐng)求錯(cuò)誤做些什么 return Promise.reject(error); }); // 添加響應(yīng)攔截器 axios.interceptors.response.use((res) => { const { status } = res; // 在發(fā)送結(jié)果之前做些什么 對(duì)錯(cuò)誤狀態(tài)提示進(jìn)行處理 //... return res.data; }, function (error) { // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么 return Promise.reject(error); }); class Http { constructor(config) { this.axios = axios; // 這里仍需對(duì)配置進(jìn)行處理,代碼省略了 this.config = config; } // Get 請(qǐng)求 get(url,params={},headers={}){ // ... } // POST 請(qǐng)求 post(url,params={},headers={}){ // ... } } export default Http; // 無(wú)特殊需求的只需使用這個(gè)一個(gè)對(duì)象即可 公共 header 可在此配置, 如需多個(gè)實(shí)例 可按照此方式創(chuàng)建多個(gè)進(jìn)行導(dǎo)出 export const Axios = new Http({ headers: { 'x-http-token': 'xxx' } });
這里不對(duì)具體的方法進(jìn)行描述,只做一個(gè)解決問(wèn)題的說(shuō)明,后續(xù)會(huì)針對(duì) axios 類的封裝,單獨(dú)寫篇文章再詳細(xì)說(shuō)明下的
以上就是axios的interceptors多次執(zhí)行問(wèn)題解決的詳細(xì)內(nèi)容,更多關(guān)于axios interceptors多次執(zhí)行的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue.js中的計(jì)算屬性、監(jiān)視屬性與生命周期詳解
最近在學(xué)習(xí)vue,學(xué)習(xí)中遇到了一些感覺(jué)挺重要的知識(shí)點(diǎn),感覺(jué)有必要整理下來(lái),這篇文章主要給大家介紹了關(guān)于Vue.js中計(jì)算屬性、監(jiān)視屬性與生命周期的相關(guān)資料,需要的朋友可以參考下2021-06-06vue項(xiàng)目中Toast字體過(guò)小,沒(méi)有邊距的解決方案
這篇文章主要介紹了vue項(xiàng)目中Toast字體過(guò)小,沒(méi)有邊距的解決方案。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04詳解vue2.0模擬后臺(tái)json數(shù)據(jù)
這篇文章主要介紹了vue2.0模擬后臺(tái)json數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05vue和iview結(jié)合動(dòng)態(tài)生成表單實(shí)例
這篇文章主要介紹了vue和iview結(jié)合動(dòng)態(tài)生成表單實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vue項(xiàng)目配置同一局域網(wǎng)可使用ip訪問(wèn)的操作
這篇文章主要介紹了vue項(xiàng)目配置同一局域網(wǎng)可使用ip訪問(wèn)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10Vue Element前端應(yīng)用開(kāi)發(fā)之echarts圖表
在我們做應(yīng)用系統(tǒng)的時(shí)候,往往都會(huì)涉及圖表的展示,綜合的圖表展示能夠給客戶帶來(lái)視覺(jué)的享受和數(shù)據(jù)直觀體驗(yàn),同時(shí)也是增強(qiáng)客戶認(rèn)同感的舉措之一2021-05-05Vue驗(yàn)證碼60秒倒計(jì)時(shí)功能簡(jiǎn)單實(shí)例代碼
這篇文章主要介紹了Vue驗(yàn)證碼60秒倒計(jì)時(shí)功能簡(jiǎn)單實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06