vue 路由攔截、axios請求攔截

路由攔截

項目中,有些頁面須要登陸後才能進入,例如,在某頁面A,用戶在操做前須要先進入登陸頁(此時須要將上一頁的地址(/survey/start)做爲query存入login頁面的地址中,如: http://localhost:8071/#/login?redirect=%2Fsurvey%2Freport),登陸成功後再進入頁面A。css

首先,在router.js中建立路由時,給須要登陸的路由中的 meta 添加字段:requireLogin,以下:html

const router = new Router({ 
  routes: [
    {
      path: '/login',
      name: 'Login',
      component: Login,
      meta: {
        title: '登陸頁'
      }
    },
    {
      path: '/register',
      name: 'Register',
      component: Register,
      meta: {
        title: '註冊頁'
      }
    },
    {
      path: '/',
      redirect: '/survey/start',
      name: 'Full',
      component: Full,
      children: [
        {
          path: '/survey/start',
          name: 'Home',
          component: Home,
          meta: {
            title: '首頁',
            requireLogin: true
          }
        },
        {
          path: '/survey/report',
          name: 'Report',
          component: Report,
          meta: {
            title: '詳情頁',
            requireLogin: true
          }
        }
      ]
    }
  ]
})

而後使用 router.beforeEach 註冊一個全局前置守衛:前端

// 全局導航鉤子
router.beforeEach((to, from, next) => {
  if (to.meta.title) { // 路由發生變化修改頁面title
      document.title = to.meta.title
  }
  if (to.meta.requireLogin) {
    if (store.state.token) {
      if (Object.keys(from.query).length === 0) { // 判斷路由來源是否有query,處理不是目的跳轉的狀況
        next()
      } else {
          let redirect = from.query.redirect // 若是來源路由有query
          if (to.path === redirect) { // 避免 next 無限循環
            next()
          } else {
            next({ path: redirect }) // 跳轉到目的路由
          }
      }
    } else {
      next({
        path: '/login',
        query: { redirect: to.fullPath } // 將跳轉的路由path做爲參數,登陸成功後跳轉到該路由
      })
    }
  } else {
      next()
  }
})

關於Vue Router導航守衛,參考:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%ABvue

axios 請求攔截

上面的方法只是進行了前端攔截,沒法肯定存儲在本地的token是否已經失效。須要 axios 攔截器:ios

在mian.js 中:axios

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Axios from 'axios'
import './assets/styles/reset.css'
import './plugins/element.js'
import htmlToPdf from './utils/htmlToPdf'

Vue.config.productionTip = false

Vue.use(htmlToPdf)

// http request 攔截器
Axios.interceptors.request.use(
  config => {
    if (sessionStorage.getItem('token')) { // 若存在token,則每一個Http Header都加上token
      config.headers.Authorization = `token ${sessionStorage.getItem('token')}`
    }
    return config;
  },
  err => {
    return Promise.reject(err);
  })

// http response 攔截器
Axios.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    if (error.response) {
      switch (error.response.status) {
        case 401:
          // 返回 401 (未受權) 清除 token 並跳轉到登陸頁面
          sessionStorage.removeItem('token')
          router.replace({
            path: 'login',
            query: {
              redirect: router.currentRoute.fullPath
            }
          })
      }
    }
    return Promise.reject(error.response.data) // 返回接口返回的錯誤信息
  }
)

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
相關文章
相關標籤/搜索