vue攔截器實(shí)現(xiàn)http+router雙攔截
vue攔截器,主要是針對(duì)數(shù)據(jù)請(qǐng)求進(jìn)行統(tǒng)一的調(diào)度,避免不同請(qǐng)求多個(gè)響應(yīng)方式,以達(dá)到在交互上的統(tǒng)一,如統(tǒng)一的錯(cuò)誤處理。在vue框架里實(shí)現(xiàn)http數(shù)據(jù)請(qǐng)求主要是通過(guò)
axios,請(qǐng)求攔截使用interceptors方法。

在實(shí)際項(xiàng)目開(kāi)發(fā)過(guò)程中,經(jīng)常有攔截請(qǐng)求、攔截響應(yīng),下面就先從這兩個(gè)方面來(lái)說(shuō)一說(shuō)。
攔截請(qǐng)求
實(shí)用的場(chǎng)景是需要在http請(qǐng)求中增加自定義的header信息,常見(jiàn)的就是在header中增加通訊簽名和憑證來(lái)防止攻擊。下面看看代碼片段:
const apiClient = axios.create({
baseURL: "/api",
});
// 攔截請(qǐng)求
apiClient.interceptors.request.use(request => { // 請(qǐng)求頭添加access_token
const token = localStorage.getItem('TOKEN') ? JSON.parse(localStorage.getItem('TOKEN')) : ''
if (token && token.access_token) {
request.headers['Access-Token'] = token.access_token.value
}
/*
* 處理post、put、delete請(qǐng)求
* 1、data為空時(shí),默認(rèn)傳一個(gè)隨機(jī)參數(shù)
* 2、根據(jù)data生成簽名
* 3、轉(zhuǎn)化data為查詢參數(shù)格式
*/
if (request.method === 'post' || request.method === 'put' || request.method === 'delete') {
// 默認(rèn)傳一個(gè)數(shù)據(jù)
if (!request.data) {
request.data = {
t: new Date().getTime()
}
}
// 請(qǐng)求頭添加簽名
request.headers.Sign = util.createSign(request.data)
// 轉(zhuǎn)化data數(shù)據(jù)格式
request.data = qs.stringify(request.data)
}
return request
}, error => {
console.error(error.message)
})
攔截響應(yīng)
這里主要是對(duì)請(qǐng)求的響應(yīng)進(jìn)行統(tǒng)一的攔截處理,常見(jiàn)的有統(tǒng)一的錯(cuò)誤響應(yīng)、判斷登錄的憑證是否過(guò)期等等。如下面代碼片段:
// 攔截響應(yīng)
apiClient.interceptors.response.use(res => {
// 響應(yīng)失敗
if (!res.data.success) {
// 請(qǐng)求失敗響應(yīng)處理
}
/**
* refresh_token過(guò)期
* 1、清空本地token
* 2、刷新頁(yè)面
*/
if (res.data.code === 401) {
localStorage.setItem('token', '')
window.location.reload()
}
return res.data;
}, error => {
console.error(error.message);
})
下面來(lái)看看統(tǒng)一的錯(cuò)誤處理,主要是http響應(yīng)的錯(cuò)誤處理。
apiClient.interceptors.response.use(undefined, (error) => {
// Errors handling
const { response } = error;
const { data } = response;
if (data) {
// 此處為錯(cuò)誤處理
notification.warning({
message: data,
});
}
});
請(qǐng)求Loading及登錄狀態(tài)處理
直接上代碼,這里只是基本的實(shí)現(xiàn)邏輯,代碼本身涉及其他依賴,并不能直接使用。
下面的片段實(shí)現(xiàn)對(duì)http請(qǐng)求的攔截處理。
// vue axios配置 發(fā)起請(qǐng)求加載loading請(qǐng)求結(jié)束關(guān)閉loading
// http request 請(qǐng)求攔截器,有token值則配置上token值
import axios from "axios";
import router from "../router";
import { Loading } from "element-ui";
import Promise from "promise";
let loadinginstace;
// http請(qǐng)求攔截器
axios.interceptors.request.use(
(request) => {
// element ui Loading方法
loadinginstace = Loading.service({
lock: true,
text: "Loading",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.3)",
customClass: "osloading",
fullscreen: true,
});
return request;
},
(error) => {
loadinginstace.close();
return Promise.reject(error);
}
);
// http response 服務(wù)器響應(yīng)攔截器,
// 攔截401,并重新跳入登頁(yè)重新獲取token
axios.interceptors.response.use(
(response) => {
// 后端響應(yīng)的數(shù)據(jù)結(jié)構(gòu)為:{code:401,data:{}}
if (response.data.code === 401) {
loadinginstace.close();
router.replace({
path: "/login",
});
} else {
loadinginstace.close();
return response.data;
}
},
(error) => {
loadinginstace.close();
if (error.response) {
let routerPath = "/login";
switch (error.response.status) {
case 401:
routerPath = "/login"
break;
case 404:
routerPath = "/404"
break;
}
router.replace({
path: routerPath,
});
}
return Promise.reject(error.response.data);
}
);
export default axios;
路由登錄驗(yàn)證處理
路由的攔截,主要的實(shí)現(xiàn)邏輯是在路由跳轉(zhuǎn)之前進(jìn)行驗(yàn)證,主要的登錄狀態(tài)的驗(yàn)證,復(fù)雜的應(yīng)用還會(huì)涉及權(quán)限的驗(yàn)證。
import auth from "@/api/auth";
auth.refreshAuth();
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requireAuth)) {
// 判斷該路由是否需要登錄權(quán)限
const isLogin = auth.checkAuth();
if (isLogin) {
// 判斷當(dāng)前的token是否存在
next();
} else {
next({
path: "/login",
});
}
} else {
next();
}
});