Search K
Appearance
Appearance
📊 SEO元描述:2024年最新Axios拦截器教程,详解请求拦截器、响应拦截器配置、Token管理、错误处理。包含完整拦截器案例,适合Vue.js开发者掌握HTTP拦截技术。
核心关键词:Axios拦截器 2024、请求拦截器、响应拦截器、Token管理、HTTP拦截、Axios中间件
长尾关键词:Axios拦截器怎么配置、请求拦截器使用方法、响应拦截器处理、Axios Token自动添加、HTTP请求统一处理
通过本节Axios拦截器,你将系统性掌握:
拦截器是什么?这是Axios提供的强大中间件机制。拦截器允许你在请求发送前和响应返回后进行统一处理,也是企业级应用开发中不可缺少的技术。
💡 学习建议:拦截器是Axios的高级特性,建议先掌握基础使用,再深入学习拦截器配置
// 🎉 基础请求拦截器配置
import axios from 'axios'
// 创建axios实例
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
// 请求拦截器
apiClient.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
console.log('发送请求:', config)
// 添加时间戳防止缓存
if (config.method === 'get') {
config.params = {
...config.params,
_t: Date.now()
}
}
// 添加请求头
config.headers['X-Requested-With'] = 'XMLHttpRequest'
return config
},
(error) => {
// 对请求错误做些什么
console.error('请求错误:', error)
return Promise.reject(error)
}
)
export default apiClient// 🎉 Token管理请求拦截器
import axios from 'axios'
import { getToken, removeToken } from '@/utils/auth'
import router from '@/router'
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
// Token管理拦截器
apiClient.interceptors.request.use(
(config) => {
// 获取存储的token
const token = getToken()
if (token) {
// 添加Authorization头
config.headers.Authorization = `Bearer ${token}`
}
// 添加其他通用头部
config.headers['Content-Type'] = config.headers['Content-Type'] || 'application/json'
config.headers['Accept'] = 'application/json'
// 添加请求ID用于追踪
config.headers['X-Request-ID'] = generateRequestId()
// 记录请求开始时间
config.metadata = { startTime: new Date() }
return config
},
(error) => {
return Promise.reject(error)
}
)
// 生成请求ID
function generateRequestId() {
return 'req_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)
}
export default apiClient// 🎉 环境相关请求拦截器
import axios from 'axios'
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
apiClient.interceptors.request.use(
(config) => {
// 开发环境添加调试信息
if (process.env.NODE_ENV === 'development') {
console.group(`🚀 API请求: ${config.method?.toUpperCase()} ${config.url}`)
console.log('请求配置:', config)
console.log('请求参数:', config.params)
console.log('请求数据:', config.data)
console.groupEnd()
}
// 生产环境添加性能监控
if (process.env.NODE_ENV === 'production') {
// 添加用户代理信息
config.headers['User-Agent'] = navigator.userAgent
// 添加页面来源
config.headers['Referer'] = window.location.href
}
// 测试环境添加特殊标识
if (process.env.NODE_ENV === 'test') {
config.headers['X-Test-Mode'] = 'true'
}
return config
},
(error) => {
if (process.env.NODE_ENV === 'development') {
console.error('❌ 请求拦截器错误:', error)
}
return Promise.reject(error)
}
)
export default apiClient// 🎉 基础响应拦截器配置
import axios from 'axios'
import { ElMessage } from 'element-plus'
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
// 响应拦截器
apiClient.interceptors.response.use(
(response) => {
// 对响应数据做点什么
console.log('收到响应:', response)
// 计算请求耗时
if (response.config.metadata) {
const duration = new Date() - response.config.metadata.startTime
console.log(`请求耗时: ${duration}ms`)
}
// 统一处理响应数据格式
const { data } = response
// 假设API返回格式: { code: 200, data: {...}, message: 'success' }
if (data.code === 200) {
return data.data // 直接返回业务数据
} else {
// 业务错误处理
ElMessage.error(data.message || '请求失败')
return Promise.reject(new Error(data.message || '请求失败'))
}
},
(error) => {
// 对响应错误做点什么
console.error('响应错误:', error)
// 网络错误处理
if (!error.response) {
ElMessage.error('网络连接失败,请检查网络')
return Promise.reject(error)
}
// HTTP状态码错误处理
const { status } = error.response
switch (status) {
case 400:
ElMessage.error('请求参数错误')
break
case 401:
ElMessage.error('未授权,请重新登录')
// 跳转到登录页
router.push('/login')
break
case 403:
ElMessage.error('拒绝访问')
break
case 404:
ElMessage.error('请求的资源不存在')
break
case 500:
ElMessage.error('服务器内部错误')
break
default:
ElMessage.error('请求失败')
}
return Promise.reject(error)
}
)
export default apiClient// 🎉 Token自动刷新响应拦截器
import axios from 'axios'
import { getToken, setToken, getRefreshToken, removeToken } from '@/utils/auth'
import router from '@/router'
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
// 是否正在刷新token
let isRefreshing = false
// 重试队列
let failedQueue = []
// 处理队列
const processQueue = (error, token = null) => {
failedQueue.forEach(({ resolve, reject }) => {
if (error) {
reject(error)
} else {
resolve(token)
}
})
failedQueue = []
}
// 响应拦截器
apiClient.interceptors.response.use(
(response) => {
return response.data
},
async (error) => {
const originalRequest = error.config
// Token过期处理
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
// 如果正在刷新token,将请求加入队列
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject })
}).then(token => {
originalRequest.headers.Authorization = `Bearer ${token}`
return apiClient(originalRequest)
}).catch(err => {
return Promise.reject(err)
})
}
originalRequest._retry = true
isRefreshing = true
const refreshToken = getRefreshToken()
if (refreshToken) {
try {
// 刷新token
const response = await axios.post('/auth/refresh', {
refresh_token: refreshToken
})
const { access_token, refresh_token: newRefreshToken } = response.data
// 保存新token
setToken(access_token, newRefreshToken)
// 更新原请求的Authorization头
originalRequest.headers.Authorization = `Bearer ${access_token}`
// 处理队列中的请求
processQueue(null, access_token)
// 重试原请求
return apiClient(originalRequest)
} catch (refreshError) {
// 刷新token失败,清除所有token并跳转登录
processQueue(refreshError, null)
removeToken()
router.push('/login')
return Promise.reject(refreshError)
} finally {
isRefreshing = false
}
} else {
// 没有refresh token,直接跳转登录
removeToken()
router.push('/login')
return Promise.reject(error)
}
}
return Promise.reject(error)
}
)
export default apiClient// 🎉 企业级完整拦截器配置
// api/interceptors.js
import axios from 'axios'
import { ElMessage, ElLoading } from 'element-plus'
import { getToken, refreshToken, removeToken } from '@/utils/auth'
import router from '@/router'
import store from '@/store'
// 创建axios实例
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
})
// 请求计数器
let requestCount = 0
let loadingInstance = null
// 显示loading
const showLoading = () => {
if (requestCount === 0) {
loadingInstance = ElLoading.service({
text: '加载中...',
background: 'rgba(0, 0, 0, 0.7)'
})
}
requestCount++
}
// 隐藏loading
const hideLoading = () => {
requestCount--
if (requestCount === 0 && loadingInstance) {
loadingInstance.close()
loadingInstance = null
}
}
// 请求拦截器
apiClient.interceptors.request.use(
(config) => {
// 显示loading(可配置)
if (config.showLoading !== false) {
showLoading()
}
// 添加token
const token = getToken()
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// 添加请求追踪ID
config.headers['X-Request-ID'] = generateRequestId()
// 添加时间戳
config.metadata = { startTime: Date.now() }
// 开发环境日志
if (process.env.NODE_ENV === 'development') {
console.log(`🚀 ${config.method?.toUpperCase()} ${config.url}`, config)
}
return config
},
(error) => {
hideLoading()
console.error('请求拦截器错误:', error)
return Promise.reject(error)
}
)
// 响应拦截器
apiClient.interceptors.response.use(
(response) => {
// 隐藏loading
hideLoading()
// 记录请求耗时
if (response.config.metadata) {
const duration = Date.now() - response.config.metadata.startTime
if (process.env.NODE_ENV === 'development') {
console.log(`⏱️ 请求耗时: ${duration}ms`)
}
// 性能监控
if (duration > 3000) {
console.warn(`⚠️ 慢请求警告: ${response.config.url} 耗时 ${duration}ms`)
}
}
// 统一响应处理
const { data } = response
// 根据业务约定处理响应
if (data.success || data.code === 200 || data.code === 0) {
return data.data || data.result || data
} else {
const message = data.message || data.msg || '请求失败'
ElMessage.error(message)
return Promise.reject(new Error(message))
}
},
async (error) => {
hideLoading()
const { response, config } = error
// 网络错误
if (!response) {
ElMessage.error('网络连接失败,请检查网络设置')
return Promise.reject(error)
}
const { status, data } = response
// 根据状态码处理
switch (status) {
case 400:
ElMessage.error(data?.message || '请求参数错误')
break
case 401:
// Token过期,尝试刷新
if (!config._retry) {
config._retry = true
try {
const newToken = await refreshToken()
config.headers.Authorization = `Bearer ${newToken}`
return apiClient(config)
} catch (refreshError) {
removeToken()
store.dispatch('user/logout')
router.push('/login')
ElMessage.error('登录已过期,请重新登录')
}
}
break
case 403:
ElMessage.error('没有权限访问该资源')
break
case 404:
ElMessage.error('请求的资源不存在')
break
case 422:
// 表单验证错误
if (data?.errors) {
const errorMessages = Object.values(data.errors).flat()
ElMessage.error(errorMessages.join(', '))
} else {
ElMessage.error(data?.message || '数据验证失败')
}
break
case 429:
ElMessage.error('请求过于频繁,请稍后再试')
break
case 500:
ElMessage.error('服务器内部错误')
break
case 502:
ElMessage.error('网关错误')
break
case 503:
ElMessage.error('服务暂时不可用')
break
default:
ElMessage.error(data?.message || `请求失败 (${status})`)
}
return Promise.reject(error)
}
)
// 生成请求ID
function generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
}
export default apiClient// 🎉 多实例拦截器管理
// api/clients.js
import axios from 'axios'
import { setupInterceptors } from './interceptors'
// 主API客户端
export const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
// 认证API客户端
export const authClient = axios.create({
baseURL: process.env.VUE_APP_AUTH_BASE_URL,
timeout: 5000
})
// 文件上传客户端
export const uploadClient = axios.create({
baseURL: process.env.VUE_APP_UPLOAD_BASE_URL,
timeout: 30000
})
// 第三方API客户端
export const thirdPartyClient = axios.create({
baseURL: process.env.VUE_APP_THIRD_PARTY_BASE_URL,
timeout: 15000
})
// 为每个客户端设置拦截器
setupInterceptors(apiClient, {
showLoading: true,
autoRefreshToken: true,
errorNotification: true
})
setupInterceptors(authClient, {
showLoading: false,
autoRefreshToken: false,
errorNotification: true
})
setupInterceptors(uploadClient, {
showLoading: true,
autoRefreshToken: true,
errorNotification: false
})
setupInterceptors(thirdPartyClient, {
showLoading: false,
autoRefreshToken: false,
errorNotification: false
})// 🎉 拦截器管理工具
// utils/interceptorManager.js
class InterceptorManager {
constructor() {
this.requestInterceptors = new Map()
this.responseInterceptors = new Map()
}
// 添加请求拦截器
addRequestInterceptor(name, fulfilled, rejected) {
const interceptor = axios.interceptors.request.use(fulfilled, rejected)
this.requestInterceptors.set(name, interceptor)
return interceptor
}
// 添加响应拦截器
addResponseInterceptor(name, fulfilled, rejected) {
const interceptor = axios.interceptors.response.use(fulfilled, rejected)
this.responseInterceptors.set(name, interceptor)
return interceptor
}
// 移除请求拦截器
removeRequestInterceptor(name) {
const interceptor = this.requestInterceptors.get(name)
if (interceptor) {
axios.interceptors.request.eject(interceptor)
this.requestInterceptors.delete(name)
}
}
// 移除响应拦截器
removeResponseInterceptor(name) {
const interceptor = this.responseInterceptors.get(name)
if (interceptor) {
axios.interceptors.response.eject(interceptor)
this.responseInterceptors.delete(name)
}
}
// 清除所有拦截器
clearAll() {
this.requestInterceptors.forEach((interceptor) => {
axios.interceptors.request.eject(interceptor)
})
this.responseInterceptors.forEach((interceptor) => {
axios.interceptors.response.eject(interceptor)
})
this.requestInterceptors.clear()
this.responseInterceptors.clear()
}
}
export default new InterceptorManager()通过本节Axios拦截器的学习,你已经掌握:
A: 请求拦截器按添加顺序的逆序执行,响应拦截器按添加顺序执行。后添加的请求拦截器先执行。
A: 可以通过导入router、store等实例,或者在拦截器配置时传入Vue实例的引用。
A: 使用队列机制,当检测到Token过期时,暂停其他请求,刷新Token后重试所有队列中的请求。
A: 使用axios.interceptors.request.eject()和axios.interceptors.response.eject()方法移除拦截器。
A: 拦截器中的错误会传递给调用的组件,可以在组件中使用try-catch或.catch()方法捕获。
// 🎉 拦截器配置检查清单
const interceptorChecklist = {
request: [
'✅ Token自动添加',
'✅ 请求头统一设置',
'✅ 请求ID生成',
'✅ 开发环境日志',
'✅ 请求时间记录'
],
response: [
'✅ 统一响应格式处理',
'✅ 错误状态码处理',
'✅ Token自动刷新',
'✅ Loading状态管理',
'✅ 性能监控记录'
]
}// 🎉 拦截器性能优化建议
const performanceOptimization = {
// 避免在拦截器中进行重计算
cacheToken: true,
// 合理使用loading状态
loadingThrottle: 300,
// 错误消息去重
errorMessageDedup: true,
// 请求队列管理
requestQueueLimit: 10
}"拦截器是Axios的核心特性,合理配置拦截器能够大幅提升开发效率和用户体验。继续学习错误处理机制,了解如何构建完整的错误处理和重试策略!"