一:什么是axios攔截器、為什么要使用axios攔截器?
在vue項目中,我們通常使用axios與后臺進行數(shù)據(jù)交互,axios是一款基于promise封裝的庫,可以運行在瀏覽器端和node環(huán)境中。它有很多優(yōu)秀的特性,例如攔截請求和響應、取消請求、轉(zhuǎn)換json、客戶端防御XSRF等。所以vue官方開發(fā)組放棄了對其官方庫vue-resource的維護,直接推薦我們使用axios庫。axios官方文檔請飛axios中文文檔
頁面發(fā)送http請求,很多情況我們要對請求和其響應進行特定的處理;例如每個請求都附帶后端返回的token,拿到response之前l(fā)oading動畫的展示等。如果請求數(shù)非常多,這樣處理起來會非常的麻煩,程序的優(yōu)雅性也會大打折扣。在這種情況下,axios為開發(fā)者提供了這樣一個API:攔截器。攔截器分為 請求(request)攔截器和 響應(response)攔截器。
二:為你的axios配置攔截器
1.axios的基礎配置
項目目錄如下圖所示:

其中,api一般存放的為頁面的請求,這些請求都需要統(tǒng)一經(jīng)過請求攔截器的處理,這部分不是重點,隨便拿出一個文件來進行展示,一看就能懂

重點在于request文件的編寫,以下是axios進行基礎配置的部分代碼
// 在http.js中引入axios
import axios from 'axios' //引入 axios
import QS from 'qs'; // 引入qs模塊,用來序列化post類型的數(shù)據(jù),某些請求會用得到
import { Message } from 'element-ui' //引入 element-ui 的 Message 模塊,用于信息提示
import store from '@/store' //引入 vuex 中的數(shù)據(jù)
import { getToken } from '@/utils/auth' //引入拿到的權(quán)限tocken
// create an axios instance 創(chuàng)建axios實例
const service = axios.create({
baseURL: process.env.BASE_API, // api 的 base_url
timeout: 5000, // request timeout 設置請求超時時間
responseType: "json",
withCredentials: true, // 是否允許帶cookie這些
headers: {
"Content-Type": "application/json;charset=utf-8"
}
})
2.axios請求攔截器
請求攔截器的作用是在請求發(fā)送前進行一些操作,例如在每個請求體里加上token,統(tǒng)一做了處理如果以后要改也非常容易。
話不多說,直接上代碼
// create an axios instance
service.interceptors.request.use(
config => {
// 在發(fā)送請求之前做什么
if (config.method === "post") {
// 序列化
// config.data = qs.stringify(config.data);
// config.data = JSON.stringify(config.data);
// 溫馨提示,若是貴公司的提交能直接接受json 格式,可以不用 qs 來序列化的
}else {
if (store.getters.token) {
// 若是有做鑒權(quán)token , 就給頭部帶上token
// 讓每個請求攜帶token-- ['X-Token']為自定義key 請根據(jù)實際情況自行修改
// 若是需要跨站點,存放到 cookie 會好一點,限制也沒那么多,有些瀏覽環(huán)境限制了 localstorage (隱身模式)的使用
config.headers['X-Token'] = getToken()
}
}
return config;
},
error => {
// 對請求錯誤做些什么,自己定義
Message({ //使用element-ui的message進行信息提示
showClose: true,
message: error,
type: "warning"
});
return Promise.reject(error);
}
這里說一下token,一般是在登錄完成之后,將用戶的token通過localStorage或者cookie存在本地,然后用戶每次在進入頁面的時候,會首先從本地存儲中讀取token,如果token存在說明用戶已經(jīng)登陸過,則更新vuex中的token狀態(tài)。然后,在每次請求接口的時候,都會在請求的header中攜帶token,服務器就可以根據(jù)你攜帶的token來判斷你的登錄是否過期,如果沒有攜帶,則說明沒有登錄過。
3.響應攔截器
響應攔截器的作用是在接收到響應后進行一些操作,例如在服務器返回登錄狀態(tài)失效,需要重新登錄的時候,跳轉(zhuǎn)到登錄頁等。
話不多說,直接上代碼
// response interceptor
service.interceptors.response.use(
response => {
// 如果返回的狀態(tài)碼為200,說明接口請求成功,可以正常拿到數(shù)據(jù)
// 否則的話拋出錯誤
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服務器狀態(tài)碼不是2開頭的的情況
// 這里可以跟你們的后臺開發(fā)人員協(xié)商好統(tǒng)一的錯誤狀態(tài)碼
// 然后根據(jù)返回的狀態(tài)碼進行一些操作,例如登錄過期提示,錯誤提示等等
// 下面列舉幾個常見的操作,其他需求可自行擴展
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登錄
// 未登錄則跳轉(zhuǎn)登錄頁面,并攜帶當前頁面的路徑
// 在登錄成功后返回當前頁面,這一步需要在登錄頁操作。
case 401:
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
break;
// 403 token過期
// 登錄過期對用戶進行提示
// 清除本地token和清空vuex中token對象
// 跳轉(zhuǎn)登錄頁面
case 403:
Message({
message: '登錄過期,請重新登錄',
duration: 1000,
forbidClick: true
});
// 清除token
localStorage.removeItem('token');
store.commit('loginSuccess', null);
// 跳轉(zhuǎn)登錄頁面,并將要瀏覽的頁面fullPath傳過去,登錄成功后跳轉(zhuǎn)需要訪問的頁面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
// 404請求不存在
case 404:
Message({
message: '網(wǎng)絡請求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他錯誤,直接拋出錯誤提示
default:
Message({
message: error.response.data.message,
duration: 1500,
forbidClick: true
});
}
return Promise.reject(error.response);
}
}
});
響應攔截器很好理解,就是服務器返回給我們的數(shù)據(jù),我們在拿到之前可以對他進行一些處理。例如:如果后臺返回的狀態(tài)碼是200,則正常返回數(shù)據(jù),否則的根據(jù)錯誤的狀態(tài)碼類型進行一些我們需要的錯誤,其實這里主要就是進行了錯誤的統(tǒng)一處理和沒登錄或登錄過期后調(diào)整登錄頁的一個操作。
4.在項目中調(diào)用攔截器
axios封裝好之后,調(diào)用就很簡單了。我們把接口統(tǒng)一寫在api文件夾中。(如果你的業(yè)務非常復雜,建議把不同模塊或組件的請求分開寫到不同的文件里,這樣方便維護)。
// api.js
import request from '@/utils/request'
export function userSearch(name) {
return request({
url: '/search/user',
method: 'get',
params: { name }
})
}
然后在具體的組件中進行調(diào)用即可
import { userSearch} from '@/api/api'
export default {
data() {
return {
name: '大大大大大西瓜G'
}
},
methods:{
getUserInfo () {
userSearch(this.name).then(res => {
//對拿到的res.data進行一番操作或者渲染
})
}
},
mounted() {
this.getUserInfo ();
}
}
好啦,以上就是今天的內(nèi)容分享。
春天來了,大家多出門走走吧!
