在处理多后端地址且拦截器逻辑各不相同的项目时,核心在于实现​​配置隔离​​和​​逻辑解耦​​。通过创建多个独立的Axios实例,并为每个实例配置专属的拦截器和默认设置,是当前最受推荐的做法。 以下是一种稳健的封装方案,你可以根据项目规模进行调整。

核心封装策略

1. 创建多个Axios实例

为每个后端服务创建独立的Axios实例,这是实现配置隔离的基础。

// src/utils/request.js
import axios from 'axios';

// 创建主业务API实例
export const mainAPI = axios.create({
  baseURL: process.env.VUE_APP_MAIN_API, // 从环境变量读取
  timeout: 10000,
});

// 创建第三方服务API实例(例如企业资源计划系统)
export const erpAPI = axios.create({
  baseURL: process.env.VUE_APP_ERP_API,
  timeout: 15000, // 该服务响应较慢,设置更长超时时间
});

// 创建文件上传服务实例
export const uploadAPI = axios.create({
  baseURL: process.env.VUE_APP_UPLOAD_API,
  timeout: 30000, // 文件上传需要更长时间
  headers: { 'Content-Type': 'multipart/form-data' }, // 专属请求头
});

2. 为每个实例配置独立的拦截器

针对每个实例的特定需求,设置专属的请求和响应拦截器。

// 主业务API拦截器
mainAPI.interceptors.request.use(
  (config) => {
    // 自动添加认证Token
    const token = localStorage.getItem('access_token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

mainAPI.interceptors.response.use(
  (response) => {
    // 统一处理主业务后端的数据返回格式
    if (response.data.code === 200) {
      return response.data;
    } else {
      // 处理业务逻辑错误
      alert(response.data.message);
      return Promise.reject(new Error(response.data.message));
    }
  },
  (error) => {
    // 统一处理HTTP错误状态码
    if (error.response?.status === 401) {
      alert('登录已过期,请重新登录');
      // 清除token并跳转到登录页
      localStorage.removeItem('access_token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

// 第三方服务拦截器(逻辑可能完全不同)
erpAPI.interceptors.request.use(
  (config) => {
    // 第三方服务可能使用不同的认证方式,例如API Key
    config.headers['API-Key'] = process.env.VUE_APP_ERP_API_KEY;
    return config;
  },
  (error) => Promise.reject(error)
);

erpAPI.interceptors.response.use(
  (response) => {
    // 第三方服务的响应结构可能不同,直接返回数据
    return response;
  },
  (error) => {
    // 对第三方服务的错误有特殊处理
    console.error('ERP接口调用失败:', error);
    return Promise.reject(error);
  }
);

3. 模块化封装与统一导出

将不同业务的API请求函数按模块分类,便于维护和管理。

// src/api/main.js (主业务API模块)
import { mainAPI } from '@/utils/request';

export const userAPI = {
  login: (data) => mainAPI.post('/user/login', data),
  getProfile: () => mainAPI.get('/user/profile'),
  updateProfile: (data) => mainAPI.put('/user/profile', data),
};

export const orderAPI = {
  list: (params) => mainAPI.get('/orders', { params }),
  detail: (id) => mainAPI.get(`/orders/${id}`),
  create: (data) => mainAPI.post('/orders', data),
};
// src/api/erp.js (ERP系统API模块)
import { erpAPI } from '@/utils/request';

export const erp = {
  getInventory: (params) => erpAPI.get('/inventory', { params }),
  updateStock: (data) => erpAPI.post('/stock/update', data),
};

4. 高级优化技巧

  • ​防止重复请求​​:在拦截器中实现取消重复请求的逻辑。
  • ​环境差异化配置​​:结合环境变量,为开发、测试、生产环境配置不同的基础地址。
  • 请求重试机制:为不稳定的服务添加有限的自动重试功能。

实践示例

在实际组件中使用封装好的API:

// 在Vue组件中使用
import { userAPI } from '@/api/main';
import { erp } from '@/api/erp';

export default {
  methods: {
    async handleLogin() {
      try {
        const result = await userAPI.login({ 
          username: 'admin', 
          password: 'password' 
        });
        // 处理登录结果
      } catch (error) {
        // 错误已由拦截器统一处理,这里可根据需要做UI层面的特殊处理
        this.$message.error('登录失败');
      }
    },
    
    async loadInventory() {
      try {
        const inventory = await erp.getInventory({ warehouse: 'default' });
        this.inventoryData = inventory;
      } catch (error) {
        // ERP接口错误处理
      }
    }
  }
}

封装的价值

通过这种封装方式,你获得了:

  • ​高度隔离​​:各后端服务配置互不干扰。
  • ​维护性强​​:相关变更影响范围小,易于调试和迭代。
  • ​开发体验好​​:业务代码简洁明了,只需关注业务逻辑。
  • ​灵活性高​​:轻松应对各后端服务的个性化需求。

这种多实例方案虽然初始设置稍显复杂,但随着项目发展,其优势会愈发明显,特别适合中大型前端项目。 希望这份详细的方案能帮助你更好地组织代码。如果你有更具体的场景或疑问,我可以提供更具针对性的建议。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]