基础HTTP请求封装:axios实例创建、baseURL、请求与响应拦截器、超时设置

1. 原理与作用

在大型应用中,直接使用 axios 裸调用会导致大量重复配置(baseURL、headers、超时),且缺少统一的请求/响应处理管道。通过创建自定义 axios 实例,可以固化全局配置,并利用拦截器(interceptors)实现请求前/响应后的统一逻辑,例如:

  • baseURL:将所有相对路径拼接为路径,便于环境切换。
  • 请求拦截器:注入 、统一加时间戳、记录日志。
  • 响应拦截器:统一解包数据、处理业务错误码、触发全局报错。
  • 超时设置:防止死连接,提升用户体验。
配置项作用推荐值
baseURL接口基础路径,环境切换时只需改一处/api/v1 或完整域名
timeout请求超时时间(毫秒)10000 ~ 30000
headers默认请求头,如 Content-Type{ 'Content-Type': 'application/json' }
withCredentials跨域携带 Cookietrue(需要 CORS 支持)

2. 实现流程

  1. 安装 axios 依赖(npm / yarn)。
  2. 创建独立文件 request.js,导出自定义实例。
  3. 通过 axios.create() 初始化实例,传入 baseURL、timeout、headers 等默认配置。
  4. 注册 请求拦截器(用 instance.interceptors.request.use):获取 localStorage 中的 ,添加到 config.headers.Authorization。
  5. 注册 响应拦截器:对成功响应解包 response.data;对失败响应统一处理错误码(如 401 跳转登录)。
  6. 在业务模块中直接引用该实例,调用 request.get('/user') 等。
关键点:拦截器必须返回 config(请求)或 response(响应),否则 Promise 链会中断。

3. 代码实现(标准封装)

以下是完整的 request.js 示例:

// request.js
import axios from 'axios'

// 1. 创建 axios 实例
const instance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout: 15000,
  headers: { 'Content-Type': 'application/json' }
})

// 2. 请求拦截器
instance.interceptors.request.use(
  config => {
    const  = localStorage.getItem('')
    if () {
      config.headers.Authorization = `Bearer ${}`
    }
    // 可选:加时间戳防缓存
    config.params = { ...config.params, _t: Date.now() }
    return config
  },
  error => Promise.reject(error)
)

// 3. 响应拦截器
instance.interceptors.response.use(
  response => {
    // 后端约定:res.data.code === 0 成功
    const res = response.data
    if (res.code !== 0) {
      // 统一错误提示
      ElMessage.error(res.msg || '请求失败')
      return Promise.reject(new Error(res.msg))
    }
    return res.data   // 解包后只返回业务数据
  },
  error => {
    if (error.code === 'ECONNABORTED') {
      ElMessage.error('请求超时,请检查网络')
    } else if (error.response) {
      const status = error.response.status
      if (status === 401) {
        localStorage.removeItem('')
        window.location.href = '/login'
      } else if (status === 500) {
        ElMessage.error('服务器异常')
      }
    } else {
      ElMessage.error('网络错误,请稍后重试')
    }
    return Promise.reject(error)
  }
)

export default instance

业务组件中使用:

import request from '@/utils/request'

export function fetchUserList(params) {
  return request.get('/user/list', { params })
}

4. 调试与验证

  • 打印拦截器日志:在请求拦截器中 console.log('request config:', config);响应拦截器中 console.log('response:', response),观察请求头、URL 是否正确。
  • 模拟超时:将 timeout 设为 1,触发 ECONNABORTED,检查错误提示。
  • 断网测试:关闭服务器或网络,验证错误拦截器是否弹出“网络错误”。
  • 跨域检查:在浏览器开发者工具 Network 面板查看请求域名是否与 baseURL 一致,CORS 头是否缺失。
调试技巧:使用 axios.interceptors.request.use 和 response.use 的第二个回调(onRejected)可以单独捕获拦截器本身的错误,避免被全局吞掉。

5. 常见错误与解决方案

错误现象原因解决
请求 URL 变成 http://localhost:3000http://.../apibaseURL 缺少尾随斜杠或请求路径baseURL 以 / 结尾,请求路径以 / 开头
拦截器中修改 config 不生效没有返回修改后的 config确保 return config
响应拦截器未捕获到业务错误码后端返回 200 但 code != 0,未在 response 中处理检查 response.data.code 逻辑
跨域请求失败(CORS)后端未设置 Access-Control-Allow-Origin后端配置或使用代理(vite proxy)
超时后重复重试导致的堆栈未限制重试次数引入 axios-retry 并限制次数

6. 性能与稳定性优化

  • 请求取消:使用 AbortController 或 CancelToken 在组件卸载时取消未完成的请求。
  • 连接池复用:浏览器自动管理 HTTP/1.1 连接池,仍可设置 keepAlive(axios 默认支持)。
  • 避免重复请求:在请求拦截器中根据 URL + 参数做防抖(debounce),相同请求未完成时复用前一次 Promise。
  • 日志采样:生产环境下关闭拦截器中的 console.log,改用指标采集。
  • 超时动态调整:根据网络类型(WiFi / 4G)调整 timeout 值。
注意:不要在响应拦截器中执行长时间同步操作(如 JSON.parse 大体积数据),避免阻塞主线程。大数据量建议在业务层处理。

7. 请求流程内部结构

下图展示了 axios 实例从创建到完成请求的完整生命周期,包含请求拦截、实际 HTTP 请求、响应拦截及错误处理分支:

axios 请求封装流程 应用层代码 axios.create() baseURL timeout | headers 请求拦截器 发送 HTTP 请求 响应拦截器 返回业务数据 错误拦截器 抛出 Promise.reject 关于超时设置 • 在 axios.create() 中设置 • 超时时触发 error.code = 'ECONNABORTED' • 可在响应错误拦截器中单独处理

8. 部署与多环境配置

推荐在 .env 文件中定义 VITE_API_BASE_URL,构建时自动注入:

# .env.development
VITE_API_BASE_URL = /api

# .env.production
VITE_API_BASE_URL = https://your-api.com/api/v1

若使用 webpack,可通过 DefinePlugin 注入 process.env.BASE_URL。拦截器中避免硬编码敏感信息,使用环境变量统一管理。

部署检查清单:
  • 确保 baseURL 指向正确的生产 API 域名。
  • 关闭所有 console.log 调试输出。
  • 响应拦截器的错误提示使用用户友好的文案。
  • CORS 配置允许生产域名跨域。