在 Vue 项目中,最稳妥的做法是在 Axios 响应拦截器中判断状态码 401,清除本地 token 并跳转登录页,但必须排除登录接口本身以避免死循环,同时需处理并发请求导致的多次跳转问题。
先说结论:拦截器处理是标准方案,重点在于防止重复跳转和登录接口误判。
- 适合单页应用(SPA)及需要统一鉴权的场景
- 先看登录接口是否也会返回 401,需做白名单豁免
- 建议增加防抖标志位,避免并发请求触发多次跳转
核心代码实现
以下是一个包含白名单判断和防抖处理的完整 Axios 拦截器示例。请注意,必须正确引入 router 实例,否则跳转逻辑无法生效。
import axios from 'axios'
import router from '@/router' // 关键:引入路由实例,路径根据项目结构调整
const loginPath = '/login' // 定义登录页白名单路径
let isReloginShow = false // 防抖标志位,防止并发请求多次跳转
axios.interceptors.response.use(response => {
return response
}, error => {
if (error.response && error.response.status === 401) {
const { config } = error
// 1. 白名单判断:如果是登录接口本身失败,不触发跳转,避免死循环
if (config.url.includes(loginPath)) {
return Promise.reject(error)
}
// 2. 防抖判断:如果正在跳转中,后续 401 请求不再重复触发
if (isReloginShow) {
return Promise.reject(error)
}
isReloginShow = true
// 3. 清除本地缓存 token 及用户信息
localStorage.removeItem('token')
// 如果使用了 Vuex/Pinia,建议同时清除 store 中的用户状态
// store.commit('CLEAR_USER_INFO')
// 4. 跳转登录页
router.push('/login')
// 5. 重置标志位(可选):防止跳转后新请求无法再次触发逻辑
setTimeout(() => { isReloginShow = false }, 5000)
}
return Promise.reject(error)
})这段代码需要放在项目初始化阶段(如 main.js 或专门的 request.js 文件中),确保所有请求都经过此拦截器。
配置步骤
1. 确认路由实例:检查项目中 router 实例的导出路径,通常在 @/router/index.js,确保拦截器文件中能正确 import。
2. 编写拦截逻辑:将上述代码复制到请求封装文件中,替换原有的简单拦截逻辑。
3. 配置白名单:根据实际后端接口定义,修改 loginPath 变量,确保登录接口 URL 匹配准确。
4. 处理并发跳转:代码中已内置 isReloginShow 标志位,无需额外配置,但需确保该变量作用域全局唯一。
5. 清理缓存:跳转前务必清除本地存储的 token 及用户信息,防止刷新后依旧携带旧 token。
怎么验证是否生效
1. 模拟过期:登录成功后,手动在浏览器 Application 面板中删除 token,或者等待 token 自然过期。
2. 触发请求:刷新页面或点击一个需要鉴权的按钮。
3. 观察网络:打开开发者工具 Network 标签,确认请求返回状态码为 401。
4. 检查跳转:确认页面 URL 变更为登录页,且本地存储中已无 token。
5. 测试登录接口:在登录页故意输入错误密码,确认不会跳转回登录页(即不会死循环),而是显示后端返回的错误消息。
常见坑与排查
1. 死循环跳转:登录接口本身鉴权失败返回 401,被拦截器捕获又跳回登录页。解决:必须在拦截器中判断请求 URL,登录接口不走 401 跳转逻辑(见代码白名单部分)。
2. 路由实例未找到:代码运行报错 Cannot read property 'push' of undefined。解决:检查 import router 路径是否正确,确保引入的是已初始化的 router 实例而非配置对象。
3. 多次弹窗:有些项目会在 401 时弹出提示框。如果没有防抖处理,并发请求会导致弹出多个提示框。解决:统一在拦截器里处理提示,或利用 isReloginShow 限制提示频率。
4. 静默刷新遗漏:部分项目采用 token 静默刷新机制。如果实现了刷新逻辑,401 拦截器需要先尝试刷新 token,刷新失败后再跳转登录,不要一遇到 401 就立刻踢用户。