Vue项目中Axios全面封装实战指南

引言

在现代前端开发中,HTTP请求是应用与后端交互的核心环节。Axios作为目前最流行的HTTP客户端库,以其简洁的API和强大的功能受到广泛青睐。然而,直接在项目中裸用Axios会导致代码冗余、维护困难等问题。本文将深入探讨如何在Vue项目中全面封装Axios,打造企业级的HTTP请求解决方案。

一、为什么需要封装Axios?

1.1 直接使用Axios的问题

  • 代码重复:每个请求都需要写完整的配置

  • 维护困难:基础配置分散在各个文件中

  • 缺乏统一错误处理

  • 难以实现请求拦截和响应拦截的统一管理

  • 类型安全缺失(TypeScript项目)

1.2 封装带来的优势

  • 统一配置和管理

  • 提高代码复用性

  • 增强错误处理能力

  • 便于实现请求拦截、身份验证等功能

  • 提升开发效率和代码质量

二、基础封装实现

2.1 项目结构规划

src/
├── api/
│   ├── index.ts          # 导出所有API
│   ├── request.ts        # Axios封装核心
│   ├── types/           # 类型定义
│   │   ├── request.ts
│   │   └── response.ts
│   ├── modules/         # 模块化API
│   │   ├── user.ts
│   │   └── product.ts
│   └── interceptors/    # 拦截器
│       ├── request.ts
│       └── response.ts

2.2 创建基础请求类

// src/api/request.ts
import axios, {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig
} from 'axios';
import { RequestConfig, RequestInterceptors, CancelRequestSource } from './types';

class Request {
  // axios实例
  instance: AxiosInstance;
  // 拦截器对象
  interceptorsObj?: RequestInterceptors;
  // 存储取消请求的Map
  cancelRequestSource: CancelRequestSource;
  // 存储所有请求url
  requests: string[];

  constructor(config: RequestConfig) {
    this.instance = axios.create(config);
    this.interceptorsObj = config.interceptors;
    this.cancelRequestSource = {};
    this.requests = [];

    // 请求拦截器
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 全局请求拦截器
        console.log('全局请求拦截器');
        
        // 添加取消令牌
        const requestId = this.generateRequestId(config);
        config.cancelToken = new axios.CancelToken(cancel => {
          this.cancelRequestSource[requestId] = cancel;
        });
        this.requests.push(requestId);

        // 自定义请求拦截器
        if (this.interceptorsObj?.requestInterceptors) {
          config = this.interceptorsObj.requestInterceptors(config);
        }
        
        return config;
      },
      (error: any) => {
        return Promise.reject(error);
      }
    );

    // 使用实例拦截器
    this.instance.interceptors.request.use(
      this.interceptorsObj?.requestInterceptors,
      this.interceptorsObj?.requestInterceptorsCatch
    );

    // 响应拦截器
    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        const requestId = this.generateRequestId(response.config);
        this.removeRequest(requestId);
        
        // 全局响应拦截器
        console.log('全局响应拦截器');
        
        // 自定义响应拦截器
        if (this.interceptorsObj?.responseInterceptors) {
          response = this.interceptorsObj.responseInterceptors(response);
        }
        
        return response.data;
      },
      (error: any) => {
        error.config && this.removeRequest(this.generateRequestId(error.config));
        
        // 全局错误处理
        if (this.interceptorsObj?.responseInterceptorsCatch) {
          return this.interceptorsObj.responseInterceptorsCatch(error);
        }
        
        // HTTP状态码错误处理
        if (error.response) {
          this.handleHttpError(error.response.status, error.response.data);
        }
        
        // 请求被取消
        if (axios.isCancel(error)) {
          console.log('请求已被取消:', error.message);
          return Promise.reject(new Error('请求已被取消'));
        }
        
        return Promise.reject(error);
      }
    );

    // 使用实例响应拦截器
    this.instance.interceptors.response.use(
      this.interceptorsObj?.responseInterceptors,
      this.interceptorsObj?.responseInterceptorsCatch
    );
  }

  /**
   * 生成请求唯一标识
   */
  private generateRequestId(config: AxiosRequestConfig): string {
    return `${config.url}-${JSON.stringify(config.params)}-${JSON.stringify(config.data)}`;
  }

  /**
   * 移除已完成/取消的请求
   */
  private removeRequest(requestId: string): void {
    const requestIndex = this.requests.indexOf(requestId);
    if (requestIndex > -1) {
      this.requests.splice(requestIndex, 1);
    }
    delete this.cancelRequestSource[requestId];
  }

  /**
   * 取消所有请求
   */
  public cancelAllRequests(): v
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值