撰于 阅读 51

vue中的请求拦截、响应拦截和全局路由拦截

1. 前言

本篇将为 axios 请求库添加请求拦截器、响应拦截器,通过它们,就可以在请求之前,或者请求结束以后定制一些个性化需求。

2. 拦截器

关于拦截器的详细文档,可访问官方地址:https://www.axios-http.cn/docs/interceptors ,官方对它的解释是:

在请求或响应被 then 或 catch 处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });

3. 整合到项目中

编辑 axios.js 文件,添加上述代码,注意,需要将实例名改成之前定义好的 instance, 代码如下:

import axios from "axios";

// 创建 Axios 实例
const instance = axios.create({
    baseURL: "/api", // 你的 API 基础 URL
    timeout: 7000, // 请求超时时间
})

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
});

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response.data
}, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error)
})

// 暴露出去
export default instance;

4. 定制请求拦截器

在用户登录成功后,我们已经将 Token 令牌存储到了 Cookie 中,但是,光存储还不够,当我们请求受保护的接口时,需要将它动态添加到请求头中才行。这个工作,就可以在请求拦截器中来完成。

4.1 给请求头添加 Token 令牌

编辑 axios.js 中请求拦截器的逻辑,代码如下:

import { getToken } from "@/composables/auth";
// 省略...

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    const token = getToken()
    console.log('统一添加请求头中的 Token:' + token)

    // 当 token 不为空时
    if (token) {
        // 添加请求头, key 为 Authorization,value 值的前缀为 'Bearer '
        config.headers['Authorization'] = 'Bearer ' + token
    }

    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
});

// 省略...

上述代码中,我们在请求拦截器中先是获取了 Cookie 中存储的 Token 令牌,在不为空的情况下,将其添加到请求头中,按后端的规范,key 为 Authorization, 值为 Bearer + 中间空一格 + 令牌 的格式。

5. 定制响应拦截器

当通过 axios 给后台服务发送请求时,若服务挂了,或者返回的状态码不在 2xx 范围内,比如 401 未授权等。我们可以统一在响应拦截器中来处理,给用户弹一个消息提示,这样交互上也更加友好。

修改响应拦截器的错误响应模块,代码如下:

import { showMessage} from '@/composables/util'
// 省略...

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 省略...
}, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么

    // 若后台有错误提示就用提示文字,默认提示为 '请求失败'
    let errorMsg = error.response.data.message || '请求失败'
    // 弹错误提示
    showMessage(errorMsg, 'error')

    return Promise.reject(error)
})

// 省略...

6. 全局路由拦截

6.1 全局前置守卫

const router = createRouter({ ... })

// 全局路由前置守卫
router.beforeEach((to, from, next) => {
    next()
})

通过使用 router.beforeEach 注册一个全局前置守卫,每个守卫默认接受两个参数:

  • to: 即将要进入的目标;
  • from: 当前导航正要离开的路由;
  • next : 可额外添加的参数,用于手动控制跳转哪个页面;

next() 必须设置,否则不会跳转目标路由。

6.2 后置钩子

有前置,就有后置。你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身,使用格式如下:

router.afterEach((to, from) => {
  
})

可以在src下新建permission.js,将前置后置守卫代码放入,然后再main.js中去引用

// 导入路由
import router from '@/router'
// 导入全局路由守卫
import '@/permission'

6.3 浏览器tab自动标题

这些信息是可以在后置路由中来获取到,然后用于动态设置页面标题,改造 permission.js , 代码如下:

// 全局路由后置守卫
router.afterEach((to, from) => {
    // 动态设置页面 Title
    let title = (to.meta.title ? to.meta.title : '') + ' - Windblog'
    document.title = title
})

6.4 路由跳转,添加登录判断


import router from '@/router/index'
import { getToken } from '@/composables/auth'
import { showMessage } from '@/composables/util'


// 全局路由前置守卫
router.beforeEach((to, from, next) => {
    console.log('==> 全局路由前置守卫')

    // 若用户想访问后台(以 /admin 为前缀的路由)
    // 未登录,则强制跳转登录页
    let token = getToken()
    if (!token && to.path.startsWith('/admin')) {
        showMessage('请先登录', 'warning')
        next({ path: '/login' })
    } else {
        next()
    }
    
})

6. 结语

本篇我们主要给 axios 添加了请求拦截器和响应拦截器,在请求拦截器中,我们统一给每次请求的请求头添加了 Token 令牌;在响应拦截器中,先是优化了获取参数的格式,然后当请求失败时,统一弹出了消息提示,让交互更加友好。也添加了路由守卫,处理页面跳转时的一些必要性逻辑。