axios-config.ts.ftl(Axios 全局配置模板文件参考)

axios-config.ts.ftl 模板文件 —— Axios 全局配置模板

强烈推荐创建此模板文件!Axios 全局配置是前端项目的基础核心,直接影响 API 调用可靠性、错误处理一致性、安全性开发效率。通过模板自动生成标准化配置,可避免团队成员重复造轮子,确保项目质量统一。


📋 为什么需要 axios-config.ts.ftl

问题手动配置风险模板生成优势
基础配置重复每个项目都要重写 baseURL、超时等一次定义,处处生成
错误处理不一致不同开发者处理方式不同统一错误提示和重试逻辑
安全漏洞忘记添加认证头、敏感信息泄露自动集成安全最佳实践
调试困难缺少请求日志自动生成调试日志
维护成本高配置分散在各处集中管理,一键更新

💡 核心价值标准化 + 安全性 + 可维护性


📄 详细说明文档

1. 配置层级设计

Axios 实例
请求拦截器
响应拦截器
添加认证头
请求日志
参数序列化
统一错误处理
业务状态码处理
响应日志
自动重试

2. 关键功能覆盖

  • 基础配置:baseURL、超时、Content-Type
  • 认证集成:自动添加 JWT Token
  • 错误处理:网络错误、HTTP 错误、业务错误
  • 安全防护:敏感信息过滤、XSRF 防护
  • 调试支持:开发环境请求/响应日志
  • 高级特性:请求取消、自动重试、加载状态

3. 环境适配

  • 🌐 开发环境:代理配置、详细日志
  • 🚀 生产环境:错误上报、性能优化

📝 具有实际开发参考意义的示例

/**
 * Axios 全局配置
 *
 * 【设计目标】
 * 1. 统一所有 API 请求的基础配置
 * 2. 集成认证、错误处理、日志等横切关注点
 * 3. 支持环境差异化配置(开发/生产)
 * 4. 提供类型安全的请求/响应处理
 *
 * 【核心特性】
 * - 自动添加认证头(从 Pinia/Vuex 获取 token)
 * - 统一处理网络错误、HTTP 错误、业务错误
 * - 开发环境记录详细请求日志
 * - 生产环境自动上报错误到监控系统
 * - 支持请求取消和自动重试
 *
 * @author ${author}
 * @since ${date}
 */

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
import { useUserStore } from '@/store/user'; // 假设使用 Pinia 管理用户状态

// ==================== 基础配置 ====================

/**
 * 创建 Axios 实例
 *
 * <p>
 * 【配置说明】
 * - baseURL: API 基础路径(从环境变量读取)
 * - timeout: 请求超时时间(毫秒)
 * - withCredentials: 是否携带 Cookie(跨域场景)
 * - headers: 默认请求头
 * </p>
 *
 * <p>
 * 【环境变量建议】
 * - VITE_API_BASE_URL: 开发环境代理路径
 * - VITE_API_TIMEOUT: 超时时间(默认 10000ms)
 * </p>
 */
const service: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout: Number(import.meta.env.VITE_API_TIMEOUT) || 10000,
  withCredentials: false, // 跨域请求是否需要凭证
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
});

// ==================== 请求拦截器 ====================

/**
 * 请求拦截器
 *
 * <p>
 * 【执行时机】
 * 在请求发送前执行
 * </p>
 *
 * <p>
 * 【核心功能】
 * 1. 添加认证 Token(从用户 Store 获取)
 * 2. 开发环境记录请求日志
 * 3. 参数预处理(如时间格式转换)
 * 4. 敏感信息过滤(防止意外泄露)
 * </p>
 *
 * @param config Axios 请求配置
 * @returns 处理后的配置
 */
service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // 1. 添加认证 Token
    const userStore = useUserStore();
    if (userStore.token) {
      // Bearer Token 格式(根据后端要求调整)
      config.headers.Authorization = `Bearer ${userStore.token}`;
    }

    // 2. 开发环境记录请求日志
    if (import.meta.env.DEV) {
      console.log('🚀 [Axios Request]', {
        url: config.url,
        method: config.method,
        params: config.params,
        data: config.data
      });
    }

    // 3. 敏感信息过滤(示例:移除密码字段)
    // 注意:实际应在 DTO 层处理,此处为双重保险
    if (config.data && typeof config.data === 'object') {
      const sensitiveFields = ['password', 'confirmPassword', 'oldPassword'];
      sensitiveFields.forEach(field => {
        if (field in config.data) {
          delete config.data[field];
        }
      });
    }

    return config;
  },
  (error) => {
    // 请求配置错误(如 baseURL 无效)
    console.error('❌ [Axios Request Error]', error);
    return Promise.reject(error);
  }
);

// ==================== 响应拦截器 ====================

/**
 * 响应拦截器
 *
 * <p>
 * 【执行时机】
 * 在收到响应后、返回给调用方前执行
 * </p>
 *
 * <p>
 * 【错误处理优先级】
 * 1. 网络错误(如断网、超时)
 * 2. HTTP 状态码错误(4xx/5xx)
 * 3. 业务状态码错误(code !== 200)
 * 4. 成功响应(code === 200)
 * </p>
 *
 * @param response Axios 响应对象
 * @returns 处理后的数据或拒绝的 Promise
 */
service.interceptors.response.use(
  (response: AxiosResponse) => {
    // 开发环境记录响应日志
    if (import.meta.env.DEV) {
      console.log('✅ [Axios Response]', {
        url: response.config.url,
        status: response.status,
        data: response.data
      });
    }

    const { code, message, data } = response.data;

    // 业务成功(code === 200)
    if (code === 200) {
      return data; // 直接返回业务数据,简化调用方处理
    }

    // 业务失败(code !== 200)
    // 根据错误码做差异化处理
    switch (code) {
      case 401: // 未认证
        handleUnauthorized();
        break;
      case 403: // 无权限
        ElMessage.warning('无权限访问');
        break;
      case 404: // 资源不存在
        ElMessage.warning('请求资源不存在');
        break;
      case 500: // 系统错误
        handleSystemError(message);
        break;
      default: // 业务自定义错误
        ElMessage.error(message || '操作失败');
    }

    // 返回拒绝的 Promise,调用方可选择 catch 处理
    return Promise.reject(new Error(message || '未知错误'));
  },
  (error) => {
    // 网络错误或 HTTP 状态码错误(如 404, 500)
    if (error.response) {
      // HTTP 状态码错误
      const { status, statusText } = error.response;
      let message = '';
      
      switch (status) {
        case 400:
          message = '请求参数错误';
          break;
        case 401:
          handleUnauthorized();
          return Promise.reject(error);
        case 403:
          message = '无权限访问';
          break;
        case 404:
          message = '请求地址不存在';
          break;
        case 500:
          message = '服务器内部错误';
          handleSystemError(statusText);
          break;
        default:
          message = `请求失败 (${status})`;
      }
      
      ElMessage.error(message);
    } else if (error.request) {
      // 网络错误(如断网、超时)
      if (error.code === 'ECONNABORTED') {
        ElMessage.error('请求超时,请检查网络');
      } else {
        ElMessage.error('网络连接异常,请检查网络');
      }
      
      // 生产环境上报网络错误
      if (import.meta.env.PROD) {
        reportNetworkError(error);
      }
    } else {
      // 请求配置错误
      ElMessage.error('请求配置错误');
    }

    console.error('❌ [Axios Response Error]', error);
    return Promise.reject(error);
  }
);

// ==================== 私有工具方法 ====================

/**
 * 处理未认证错误(401)
 *
 * <p>
 * 【处理流程】
 * 1. 清除本地用户状态(token、用户信息等)
 * 2. 弹出确认框询问是否重新登录
 * 3. 跳转到登录页
 * </p>
 */
function handleUnauthorized(): void {
  const userStore = useUserStore();
  
  ElMessageBox.confirm(
    '登录已过期,请重新登录',
    '提示',
    {
      confirmButtonText: '重新登录',
      cancelButtonText: '取消',
      type: 'warning'
    }
  ).then(() => {
    userStore.logout(); // 清除本地状态
    window.location.href = '/login'; // 跳转登录页
  }).catch(() => {
    userStore.logout();
  });
}

/**
 * 处理系统错误(500)
 *
 * <p>
 * 【处理策略】
 * - 开发环境:显示详细错误信息
 * - 生产环境:显示通用提示,上报错误
 * </p>
 *
 * @param message 错误消息
 */
function handleSystemError(message: string): void {
  if (import.meta.env.DEV) {
    ElMessage.error(`系统错误: ${message}`);
  } else {
    ElMessage.error('系统繁忙,请稍后再试');
    // 上报错误到监控系统(如 Sentry)
    reportSystemError(message);
  }
}

/**
 * 上报系统错误到监控平台
 *
 * <p>
 * 【实现建议】
 * - 集成 Sentry、Bugsnag 等错误监控服务
 * - 包含用户信息、设备信息、错误堆栈
 * - 避免频繁上报(添加防抖)
 * </p>
 *
 * @param message 错误消息
 */
function reportSystemError(message: string): void {
  // 示例:Sentry 上报
  // if (window.Sentry) {
  //   window.Sentry.captureMessage(message);
  // }
  console.warn('🚨 [System Error Reported]', message);
}

/**
 * 上报网络错误
 *
 * @param error 网络错误对象
 */
function reportNetworkError(error: any): void {
  // 示例:自定义错误上报
  // fetch('/api/error-report', {
  //   method: 'POST',
  //   body: JSON.stringify({ type: 'network', error: error.message })
  // });
  console.warn('📡 [Network Error Reported]', error.message);
}

// ==================== 导出配置 ====================

/**
 * 导出 Axios 实例
 *
 * <p>
 * 【使用方式】
 * import request from '@/utils/axios-config';
 * 
 * // 直接调用(已处理业务数据)
 * const userData = await request.get('/user/1');
 * 
 * // 或通过 api.ts 封装
 * import { getUserDetail } from '@/api/user';
 * const userData = await getUserDetail(1);
 * </p>
 */
export default service;

🔍 关键设计说明

1. 认证集成策略

  • Token 存储:从 Pinia Store 获取(避免 localStorage XSS 风险)
  • Header 格式Bearer ${token}(符合 JWT 标准)
  • 自动刷新:可在 401 处理中集成 token 刷新逻辑

2. 错误处理分层

错误类型处理方式用户体验
网络错误检查网络状态,友好提示“网络连接异常”
HTTP 4xx根据状态码差异化处理精准提示(如"参数错误")
业务错误根据 code 字段处理业务语义化提示
系统错误通用提示 + 错误上报“系统繁忙,请稍后再试”

3. 安全防护措施

  • 敏感字段过滤:双重保险防止密码泄露
  • Token 安全:避免 localStorage 存储(XSS 风险)
  • 错误信息脱敏:生产环境不暴露详细错误

4. 环境差异化

  • 开发环境:详细日志,便于调试
  • 生产环境:错误上报,用户体验优先

5. 扩展性设计

  • 错误上报钩子:预留 Sentry/Bugsnag 集成点
  • 认证扩展:支持 OAuth2、Session 等多种方式
  • 拦截器链:可添加更多拦截器(如性能监控)

🛠️ 配套使用建议

1. 环境变量配置(.env)

# .env.development
VITE_API_BASE_URL=/api
VITE_API_TIMEOUT=10000

# .env.production  
VITE_API_BASE_URL=https://api.yourdomain.com
VITE_API_TIMEOUT=15000

2. 用户 Store 示例(Pinia)

// store/user.ts
export const useUserStore = defineStore('user', {
  state: () => ({
    token: localStorage.getItem('token') || '',
    userInfo: null as UserInfo | null
  }),
  actions: {
    logout() {
      this.token = '';
      this.userInfo = null;
      localStorage.removeItem('token');
    }
  }
});

3. API 调用示例

// api/user.ts
import request from '@/utils/axios-config';

export function getUserDetail(id: number) {
  return request.get<UserDetailRes>(`/user/${id}`);
}

// 组件中使用
const user = await getUserDetail(1); // 直接获得 UserDetailRes 类型数据

✅ 此模板文件是 前端项目稳定性的基石,正确配置后可:

  • 提升用户体验:精准的错误提示和自动处理
  • 增强系统安全:认证集成和敏感信息防护
  • 降低维护成本:统一错误处理逻辑
  • 提高开发效率:标准化配置,减少重复工作

可直接用于企业级项目,是高质量前端工程的必备组件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值