在開發vue項目中,請求是不可缺少的,在發送請求時常常需要統一處理一些請求頭參數等設置與響應事件,這時利用請求攔截器再好不過。
這里以axios請求為例
實現了設置統一請求頭添加token, 其中token在登錄時被存入了localStorage中。
同時攔截器利用new cancelToken與定義的cancelPending方法實現了可以取消正在pending狀態的請求,什么情況會需要取消請求呢?
如下兩種情況:
1. 有一個局部分頁時,用戶快速點擊第2頁,然后繼續點擊第3頁,如果網絡不太穩定時,第2頁的請求正在發送中,還未響應,但第3頁的請求先響應了,過了一會第2 頁請求才響應,這時用戶處於第3頁,但看到的數據確是第2頁的,當然有人會說可以在發送請求過程中禁用掉分頁按鈕點擊,但我感覺體驗不太好,為何禁用呢,直接點擊第3頁時中斷掉之前相同的請求即可。
2. 切換路由時,上一路由頁面中仍有未響應的請求時切換了路由,應該把正在pending的所有請求中斷取消掉。
下面是完整實現axios請求攔截器與取消pending請求功能的代碼
let pending = []; let cancelToken = axios.CancelToken; let cancelPending = (config) => { pending.forEach((item, index) => { if(!!config){ if(item.u == config.url){ item.f(); //取消請求 pending.splice(index, 1); //移除當前請求記錄 }; }else{ item.f(); //取消請求 pending.splice(index, 1); //移除當前請求記錄 } }); }; //驗證登錄狀態 router.beforeEach((to, from, next) => { //如果是需要驗證登錄狀態的頁面 if(to.matched.some(record => record.meta.requireAuth)){ let token = localStorage.getItem('token'); //如果已經登錄,則正常進入 if(!!token){ cancelPending(); next(); }else{ next({'name': 'login', 'query': {'redirect': to.fullPath}}); }; }else if(to.name == 'login'){ //如果是登錄頁,則驗證如果當前是登錄狀態自動跳轉至系統主頁,否則正常進入登錄頁 let token = localStorage.getItem('token'); //如果已經登錄,則重定向至系統首頁 if(!!token){ router.push({'name': 'SystemWelcome'}); }else{ next(); }; }else{ //其他頁面正常進入 next(); }; }); //axios 請求攔截器 axios.interceptors.request.use(config => { let token = localStorage.getItem('token'); if (!!token) { // 判斷是否存在token,如果存在的話,則每個http header都加上token config.headers.Authorization = `token ${token}`; }; cancelPending(config); config.cancelToken = new cancelToken((c) => { pending.push({'u': config.url, 'f': c}); }); return config; }, err => { return Promise.reject(err); }); //響應攔截器 axios.interceptors.response.use(response => { cancelPending(response.config); return response; }, error => { if (error.response) { switch (error.response.status) { case 401: // 返回 401 清除token信息並跳轉到登錄頁面 localStorage.removeItem('token'); router.push({'name': 'login', 'query': {'redirect': router.currentRoute.fullPath}}); } } return {data: {}}; // 返回接口返回的錯誤信息(這里返回空對象是為了避免控制台報錯) });
