Vue2學習小記-給Vue2路由導航鉤子和axios攔截器做個封裝

景科同學發表於2019-03-04

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的資訊?請移步這裡

這個封裝很簡單,面對複雜的業務肯定還需要更多的考量,但是對於一般的小專案或邊緣業務也差不多夠用了。最後希望這篇文章能對有需要的同學提供一些幫助。

相關文章