Skip to content

Axios拦截器2024:请求响应拦截器配置完整指南

📊 SEO元描述:2024年最新Axios拦截器教程,详解请求拦截器、响应拦截器配置、Token管理、错误处理。包含完整拦截器案例,适合Vue.js开发者掌握HTTP拦截技术。

核心关键词:Axios拦截器 2024、请求拦截器、响应拦截器、Token管理、HTTP拦截、Axios中间件

长尾关键词:Axios拦截器怎么配置、请求拦截器使用方法、响应拦截器处理、Axios Token自动添加、HTTP请求统一处理


📚 Axios拦截器学习目标与核心收获

通过本节Axios拦截器,你将系统性掌握:

  • 拦截器概念理解:深入理解拦截器的工作原理和应用场景
  • 请求拦截器配置:掌握请求拦截器的配置和使用方法
  • 响应拦截器处理:学会响应拦截器的数据处理和错误处理
  • Token管理机制:实现自动Token添加和刷新机制
  • 统一错误处理:构建完整的错误处理和用户反馈系统
  • 拦截器最佳实践:掌握拦截器在实际项目中的最佳实践

🎯 适合人群

  • Vue.js开发者的HTTP请求优化需求
  • 前端架构师的请求统一处理设计
  • 全栈开发者的前后端交互优化
  • 企业级开发者的API管理和安全处理

🌟 拦截器是什么?为什么重要?

拦截器是什么?这是Axios提供的强大中间件机制。拦截器允许你在请求发送前和响应返回后进行统一处理,也是企业级应用开发中不可缺少的技术。

拦截器的核心价值

  • 🎯 统一处理:在一个地方处理所有请求和响应的通用逻辑
  • 🔧 Token管理:自动添加认证Token和处理Token过期
  • 💡 错误处理:统一处理API错误和网络异常
  • 📚 数据转换:统一的数据格式化和转换
  • 🚀 性能监控:记录请求时间和性能指标

💡 学习建议:拦截器是Axios的高级特性,建议先掌握基础使用,再深入学习拦截器配置

请求拦截器配置

基础请求拦截器

javascript
// 🎉 基础请求拦截器配置
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管理拦截器

javascript
// 🎉 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

环境相关拦截器

javascript
// 🎉 环境相关请求拦截器
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

响应拦截器配置

基础响应拦截器

javascript
// 🎉 基础响应拦截器配置
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刷新拦截器

javascript
// 🎉 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

完整拦截器配置

企业级拦截器配置

javascript
// 🎉 企业级完整拦截器配置
// 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

多实例拦截器管理

javascript
// 🎉 多实例拦截器管理
// 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
})

拦截器工具函数

拦截器管理工具

javascript
// 🎉 拦截器管理工具
// 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拦截器学习总结与下一步规划

✅ 本节核心收获回顾

通过本节Axios拦截器的学习,你已经掌握:

  1. 拦截器概念理解:深入理解了拦截器的工作原理和应用场景
  2. 请求拦截器配置:掌握了Token管理、请求头添加等请求拦截功能
  3. 响应拦截器处理:学会了统一响应处理、错误处理和Token刷新
  4. 企业级配置:构建了完整的企业级拦截器配置方案
  5. 多实例管理:掌握了多个Axios实例的拦截器管理方法

🎯 拦截器下一步

  1. 错误处理机制:深入学习完整的错误处理和重试策略
  2. 请求取消:学习如何取消不需要的请求和避免竞态条件
  3. 性能监控:实现请求性能监控和分析
  4. 安全增强:学习请求签名、加密等安全措施

🔗 相关学习资源

💪 实践建议

  1. 拦截器配置:为项目配置完整的请求和响应拦截器
  2. 错误处理完善:建立完整的错误处理和用户反馈机制
  3. 性能监控:添加请求性能监控和分析功能
  4. 安全加固:实现Token自动刷新和安全防护

🔍 常见问题FAQ

Q1: 拦截器的执行顺序是什么?

A: 请求拦截器按添加顺序的逆序执行,响应拦截器按添加顺序执行。后添加的请求拦截器先执行。

Q2: 如何在拦截器中访问Vue实例?

A: 可以通过导入router、store等实例,或者在拦截器配置时传入Vue实例的引用。

Q3: Token刷新时如何处理并发请求?

A: 使用队列机制,当检测到Token过期时,暂停其他请求,刷新Token后重试所有队列中的请求。

Q4: 如何动态添加或移除拦截器?

A: 使用axios.interceptors.request.eject()和axios.interceptors.response.eject()方法移除拦截器。

Q5: 拦截器中的错误如何传递给组件?

A: 拦截器中的错误会传递给调用的组件,可以在组件中使用try-catch或.catch()方法捕获。


🛠️ 拦截器最佳实践

拦截器配置检查清单

javascript
// 🎉 拦截器配置检查清单
const interceptorChecklist = {
  request: [
    '✅ Token自动添加',
    '✅ 请求头统一设置',
    '✅ 请求ID生成',
    '✅ 开发环境日志',
    '✅ 请求时间记录'
  ],
  
  response: [
    '✅ 统一响应格式处理',
    '✅ 错误状态码处理',
    '✅ Token自动刷新',
    '✅ Loading状态管理',
    '✅ 性能监控记录'
  ]
}

拦截器性能优化

javascript
// 🎉 拦截器性能优化建议
const performanceOptimization = {
  // 避免在拦截器中进行重计算
  cacheToken: true,
  
  // 合理使用loading状态
  loadingThrottle: 300,
  
  // 错误消息去重
  errorMessageDedup: true,
  
  // 请求队列管理
  requestQueueLimit: 10
}

"拦截器是Axios的核心特性,合理配置拦截器能够大幅提升开发效率和用户体验。继续学习错误处理机制,了解如何构建完整的错误处理和重试策略!"