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的資訊?請移步這裡。
這個封裝很簡單,面對複雜的業務肯定還需要更多的考量,但是對於一般的小專案或邊緣業務也差不多夠用了。最後希望這篇文章能對有需要的同學提供一些幫助。