共计 3089 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点
在前后端分离项目中,每次请求都需要携带 Token 进行身份认证。手动处理方式存在三大问题:

- 重复代码 :每个请求都需要显式添加
headers: {Authorization: 'Bearer xxx'} - 维护困难 :Token 变更时需要修改所有请求调用处
- 安全风险 :容易遗漏添加导致接口鉴权失败
技术方案对比
方案 1:手动添加(不推荐)
// 每个请求都需要重复写 header
axios.get('/api/data', {headers: { Authorization: 'Bearer' + store.state.token}
})
方案 2:封装 request 函数
function request(config) {
return axios({
...config,
headers: {Authorization: 'Bearer' + getToken(),
...config.headers
}
})
}
方案 3:拦截器方案(推荐)
// 一次配置,全局生效
axios.interceptors.request.use(config => {config.headers.Authorization = `Bearer ${token}`
return config
})
优势对比 :
– 手动添加:维护成本最高
– 函数封装:需要改造所有调用方式
– 拦截器:无侵入式改造,集中管理
核心实现
1. 基础拦截器配置
/**
* 请求拦截器配置
* @param {import('axios').AxiosRequestConfig} config
*/
const requestInterceptor = (config) => {
const token = store.state.user.token
if (token && !config.headers.Authorization) {config.headers.Authorization = `Bearer ${token}`
config.headers['Content-Type'] = 'application/json'
}
return config
}
// 注册拦截器
axios.interceptors.request.use(requestInterceptor)
2. 响应拦截器处理 401
axios.interceptors.response.use(
response => response,
error => {if (error.response?.status === 401) {router.push('/login')
}
return Promise.reject(error)
}
)
安全实践
1. Token 刷新机制
let isRefreshing = false
axios.interceptors.response.use(null, async error => {if (error.response?.status === 401 && !isRefreshing) {
isRefreshing = true
try {const { token} = await refreshToken()
store.commit('UPDATE_TOKEN', token)
error.config.headers.Authorization = `Bearer ${token}`
return axios(error.config)
} finally {isRefreshing = false}
}
return Promise.reject(error)
})
2. 防止重复注册
// 单例模式管理拦截器
let requestInterceptorId
function setupInterceptors() {if (requestInterceptorId !== undefined) {axios.interceptors.request.eject(requestInterceptorId)
}
requestInterceptorId = axios.interceptors.request.use(requestInterceptor)
}
避坑指南
1. 文件上传处理
// 遇到 FormData 时移除 Content-Type
axios.interceptors.request.use(config => {if (config.data instanceof FormData) {delete config.headers['Content-Type'] // 浏览器会自动生成 multipart/form-data
}
return config
})
2. 内存泄漏防范
// Vue 组件卸载时
onUnmounted(() => {axios.interceptors.request.eject(requestInterceptorId)
})
完整示例
import axios from 'axios'
import store from '@/store'
import router from '@/router'
// 请求拦截器
const requestInterceptor = config => {
const token = store.state.user.token
if (token) {
config.headers = {
...config.headers,
Authorization: `Bearer ${token}`,
'Content-Type': config.data instanceof FormData
? undefined
: 'application/json'
}
}
return config
}
// 响应拦截器
const errorInterceptor = async error => {
const originalRequest = error.config
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
try {const { token} = await refreshToken()
store.commit('UPDATE_TOKEN', token)
originalRequest.headers.Authorization = `Bearer ${token}`
return axios(originalRequest)
} catch (e) {router.push('/login?expired=1')
return Promise.reject(e)
}
}
return Promise.reject(error)
}
// 注册拦截器
const requestInterceptorId = axios.interceptors.request.use(requestInterceptor)
axios.interceptors.response.use(response => response, errorInterceptor)
// 导出清理方法
export function clearInterceptors() {axios.interceptors.request.eject(requestInterceptorId)
}
总结
通过 axios 拦截器实现 Token 自动注入,我们获得了:
- 开发效率提升 :无需关心每个请求的鉴权头设置
- 统一错误处理 :401 状态码自动跳转登录页
- 安全增强 :Token 刷新机制避免频繁重新登录
- 可维护性 :所有鉴权逻辑集中在拦截器模块
实际项目中建议结合路由守卫实现完整的鉴权流程,并注意在 SPA 应用切换用户时及时清理旧拦截器。这种模式也适用于其他需要统一处理的请求逻辑,如埋点上报、性能监控等场景。
正文完
