最近在學習Vue2,遇到有些頁面請求數據需要用戶登錄許可權、伺服器響應不符預期的問題,但是總不能每個頁面都做單獨處理吧,於是想到axios提供了攔截器這個好東西,再於是就出現了本文。用戶鑒權與重定向:使用Vue提供的路由導航鉤子;請求數據序列化:使用axios提供的請求攔截器;介面報錯信息處理:使用a... ...
1.寫在前面
最近在學習Vue2,遇到有些頁面請求數據需要用戶登錄許可權、伺服器響應不符預期的問題,但是總不能每個頁面都做單獨處理吧,於是想到axios提供了攔截器這個好東西,再於是就出現了本文。
2.具體需求
- 用戶鑒權與重定向:使用Vue提供的路由導航鉤子
- 請求數據序列化:使用axios提供的請求攔截器
- 介面報錯信息處理:使用axios提供的響應攔截器
3.簡單實現
3.1 路由導航鉤子層面鑒權與重定向的封裝
路由導航鉤子所有配置均在router/index.js,這裡是部分代碼
import Vue from 'vue'
import Router from 'vue-router'
import { getUserData } from '@/script/localUserData'
const MyAddress = r => require.ensure([], () => r(require('@/views/MyAddress/MyAddress')), 'MyAddress')
Vue.use(Router)
const routes = [
{
path: '/profile/address',
name: 'MyAddress',
component: MyAddress,
meta: {
title: '我的地址',
requireAuth: true
}
},
// 更多...
]
const router = new Router({
mode: 'history',
routes
})
我們主要來看下麵邏輯處理部分的代碼
let indexScrollTop = 0
router.beforeEach((to, from, next) => {
// 路由進入下一個路由對象前,判斷是否需要登陸
// 在路由meta對象中由個requireAuth欄位,只要此欄位為true,必須做鑒權處理
if (to.matched.some(res => res.meta.requireAuth)) {
// userData為存儲在本地的一些用戶信息
let userData = getUserData()
// 未登錄和已經登錄的處理
// getUserData方法處理後如果userData.token沒有值就是undefined,下麵直接判斷
if (userData.token === undefined) {
// 執行到此處說明沒有登錄,君可按需處理之後再執行如下方法去登錄頁面
// 我這裡沒有其他處理,直接去了登錄頁面
next({
path: '/login',
query: {
redirect: to.path
}
})
} else {
// 執行到說明本地存儲有用戶信息
// 但是用戶信息是否過期還是需要驗證一下滴
let overdueTime = userData.overdueTime
let nowTime = +new Date
// 登陸過期和未過期
if (nowTime > overdueTime) {
// 登錄過期的處理,君可按需處理之後再執行如下方法去登錄頁面
// 我這裡沒有其他處理,直接去了登錄頁面
next({
path: '/login',
query: {
redirect: to.path
}
})
} else {
next()
}
}
} else {
next()
}
if (to.path !== '/') {
indexScrollTop = document.body.scrollTop
}
document.title = to.meta.title || document.title
})
router.afterEach(route => {
if (route.path !== '/') {
document.body.scrollTop = 0
} else {
Vue.nextTick(() => {
document.body.scrollTop = indexScrollTop
})
}
})
export default router
至此,路由鉤子層面的鑒權處理完畢,不過細心的你可能註意到:導航去登錄頁面調用的next方法裡面有個query對象,攜帶了目標路由的地址,這是因為在登錄成功後我們需要重定向到目標頁面。
3.2 對axios攔截器封裝
axios所有配置均在件script/getData.js文件,這裡是本文件公共代碼部分
```
import qs from 'qs'
import { getUserData } from '@/script/localUserData'
import router from '@/router'
import axios from 'axios'
import { AJAX_URL } from '@/config/index'
axios.defaults.baseURL = AJAX_URL
> axios請求攔截器代碼
```
/**
* 請求攔截器,請求發送之前做些事情
*/
axios.interceptors.request.use(
config => {
// POST || PUT || DELETE請求時先格式化data數據
// 這裡需要引入第三方模塊qs
if (
config.method.toLocaleUpperCase() === 'POST' ||
config.method.toLocaleUpperCase() === 'PUT' ||
config.method.toLocaleUpperCase() === 'DELETE'
) {
config.data = qs.stringify(config.data)
}
// 配置Authorization參數攜帶用戶token
let userData = getUserData()
if (userData.token) {
config.headers.Authorization = userData.token
}
return config
},
error => {
// 此處應為彈窗顯示具體錯誤信息,因為是練手項目,劣者省略此處
// 君可自行寫 || 引入第三方UI框架
console.error(error)
return Promise.reject(error)
}
)
axios響應攔截器代碼
/**
* 響應攔截器,請求返回異常統一處理
*/
axios.interceptors.response.use(
response => {
// 這段代碼很多場景下沒用
if (response.data && response.data.success === false) {
// 根據實際情況的一些處理邏輯...
return Promise.reject(response)
}
return response
},
error => {
// 此處報錯可能因素比較多
// 1.需要授權處用戶還未登錄,因為路由段有驗證是否登陸,此處理論上不會出現
// 2.需要授權處用戶登登錄過期
// 3.請求錯誤 4xx
// 5.伺服器錯誤 5xx
// 關於鑒權失敗,與後端約定狀態碼為500
switch (error.response.status) {
case 403:
// 一些處理...
break
case 404:
// 一些處理...
break
case 500:
let userData = getUserData()
if (userData.token === undefined) {
// 此處為未登錄處理
// 一些處理之後...再去登錄頁面...
// router.push({
// path: '/login'
// })
} else {
let overdueTime = userData.overdueTime
let nowTime = +new Date
if (overdueTime && nowTime > overdueTime) {
// 此處登錄過期的處理
// 一些處理之後...再去登錄頁面...
// router.push({
// path: '/login'
// })
} else {
// 極端情況,登錄未過期,但是不知道哪兒錯了
// 按需處理吧...我暴力回到了首頁
router.push({
path: '/'
})
}
}
break
case 501:
// 一些處理...
break
default:
// 狀態碼辣麽多,按需配置...
break
}
return Promise.reject(error)
}
)
想瞭解更多關於axios的信息?請移步這裡。
這個封裝很簡單,面對複雜的業務肯定還需要更多的考量,但是對於一般的小項目或邊緣業務也差不多夠用了。最後希望這篇文章能對有需要的同學提供一些幫助。