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 令牌;在响应拦截器中,先是优化了获取参数的格式,然后当请求失败时,统一弹出了消息提示,让交互更加友好。也添加了路由守卫,处理页面跳转时的一些必要性逻辑。