一个基于 axios 的请求封装工具 - request-fruge365

发布于:2025-09-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

🚀 发布了一个基于 axios 的请求封装工具 - request-fruge365

前言

在前端开发中,HTTP 请求是必不可少的功能。虽然 axios 已经很好用了,但在实际项目中,我们经常需要处理 token 管理、重复请求取消、错误统一处理等问题。每个项目都要重复写这些逻辑,既麻烦又容易出错。

于是我封装了一个基于 axios 的请求工具 request-fruge365,解决了这些痛点,让 HTTP 请求变得更简单、更可靠。

✨ 核心特性

🔄 自动 Token 处理

  • 自动从 localStorage/sessionStorage 读取 token
  • 支持自定义 token 键名和前缀
  • 401 时自动清除 token 并执行回调

🚫 重复请求取消

  • 自动识别相同请求(基于 method + url)
  • 取消前一个未完成的请求,避免重复提交
  • 支持单独禁用某个请求的取消功能

🛡️ 完整错误处理

  • 完整的 HTTP 状态码映射(400-504)
  • 业务状态码处理,支持多个成功状态码
  • 网络错误、超时错误统一处理
  • 可选的控制台日志输出

⚙️ 灵活配置

  • 支持实例级和请求级配置
  • 动态传入参数,请求级配置会覆盖实例级
  • 支持多场景适配(Web、小程序、Node.js)

📝 TypeScript 支持

  • 完整的类型定义
  • 良好的开发体验和代码提示

🚀 快速开始

安装

npm install request-fruge365

基础使用

import request from 'request-fruge365';

// GET 请求
const users = await request({
  url: '/api/users',
  method: 'get',
  params: { page: 1, size: 10 }
});

// POST 请求
const result = await request({
  url: '/api/users',
  method: 'post',
  data: { name: 'test', age: 25 }
});

自定义配置

import { createRequest } from 'request-fruge365';

const api = createRequest({
  proxyURL: 'https://api.example.com',
  timeout: 10000,
  enableLog: true,
  tokenKey: 'access_token',
  tokenPrefix: 'Bearer',
  onUnauthorized: () => {
    window.location.href = '/login';
  }
});

🔧 实际应用场景

场景一:处理不同的业务状态码

不同的后端 API 可能返回不同的成功状态码,有些返回 code: 200,有些返回 code: 0,还有些返回 code: 'success'

// 支持单个状态码
const result1 = await request({
  url: '/api/third-party',
  method: 'get',
  successCode: 0
});

// 支持多个状态码
const result2 = await request({
  url: '/api/legacy-system',
  method: 'get',
  successCode: [0, 200, 'success']
});

场景二:文件上传下载

// 文件上传
const formData = new FormData();
formData.append('file', file);

const uploadResult = await request({
  url: '/api/upload',
  method: 'post',
  data: formData,
  headers: {
    'Content-Type': 'multipart/form-data'
  },
  onUploadProgress: (progressEvent) => {
    const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
    console.log(`上传进度: ${percent}%`);
  }
});

// 文件下载
const downloadResult = await request({
  url: '/api/download/file.pdf',
  method: 'get',
  responseType: 'blob',
  onDownloadProgress: (progressEvent) => {
    const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
    console.log(`下载进度: ${percent}%`);
  }
});

场景三:防重复提交

在表单提交时,用户可能会多次点击提交按钮,导致重复请求。

// 默认启用重复请求取消
const submitResult = await request({
  url: '/api/submit-form',
  method: 'post',
  data: formData
});

// 对于轮询接口,可以禁用取消功能
const pollingResult = await request({
  url: '/api/polling',
  method: 'get',
  enableCancel: false
});

📁 API 文件封装最佳实践

在实际项目中,推荐创建统一的 API 文件来管理所有接口:

// api/index.js
import { createRequest } from 'request-fruge365';

const request = createRequest({
  proxyURL: process.env.VUE_APP_API_URL || '/api',
  enableLog: process.env.NODE_ENV === 'development',
  timeout: 10000,
  onUnauthorized: () => {
    window.location.href = '/login';
  }
});

// 用户管理 API
export const userApi = {
  getUserList(query) {
    return request({
      url: '/users',
      method: 'get',
      params: query
    });
  },

  createUser(data) {
    return request({
      url: '/users',
      method: 'post',
      data
    });
  },

  updateUser(id, data) {
    return request({
      url: `/users/${id}`,
      method: 'put',
      data
    });
  },

  deleteUser(id) {
    return request({
      url: `/users/${id}`,
      method: 'delete'
    });
  }
};

在组件中使用:

import { userApi } from '@/api';

export default {
  async mounted() {
    const users = await userApi.getUserList({ page: 1, size: 10 });
    console.log(users);
  },
  
  methods: {
    async handleCreate(formData) {
      try {
        await userApi.createUser(formData);
        this.$message.success('创建成功');
      } catch (error) {
        this.$message.error('创建失败');
      }
    }
  }
};

🌟 不同环境配置

开发环境 vs 生产环境

// 开发环境
const devApi = createRequest({
  proxyURL: 'http://localhost:3000/api',
  enableLog: true,  // 开启日志
  timeout: 10000
});

// 生产环境
const prodApi = createRequest({
  proxyURL: 'https://api.prod.com',
  enableLog: false,  // 关闭日志
  timeout: 5000,
  onUnauthorized: () => {
    window.location.href = '/login';
  }
});

微信小程序适配

const wxApi = createRequest({
  proxyURL: 'https://api.weixin.com',
  tokenKey: 'wx_token',
  tokenPrefix: 'WX-Token',
  successCode: 0,  // 微信 API 通常返回 0 表示成功
  onUnauthorized: () => {
    wx.navigateTo({ url: '/pages/login/login' });
  }
});

🔍 技术实现细节

重复请求取消机制

使用 axios 的 CancelToken 实现:

// 基于 method + url 生成唯一键
const requestKey = `${config.method}_${config.url}`;

// 如果存在相同请求,取消前一个
if (cancelTokens[requestKey]) {
  cancelTokens[requestKey].cancel('重复请求被取消');
  delete cancelTokens[requestKey];
}

// 为当前请求创建新的 CancelToken
cancelTokens[requestKey] = axios.CancelToken.source();
config.cancelToken = cancelTokens[requestKey].token;

多状态码支持

// 支持数组形式的多个成功状态码
if (Array.isArray(currentSuccessCode)) {
  isSuccess = currentSuccessCode.includes(data.code);
} else {
  isSuccess = data.code === currentSuccessCode;
}

双模块格式支持

为了兼容不同的项目环境,同时提供 ESM 和 CommonJS 两种格式:

{
  "main": "lib/index.cjs.js",    // CommonJS 入口
  "module": "index.js",          // ESM 入口
  "types": "index.d.ts",         // TypeScript 类型
  "exports": {
    ".": {
      "import": "./index.js",
      "require": "./lib/index.cjs.js",
      "types": "./index.d.ts"
    }
  }
}

📊 与其他方案对比

特性 request-fruge365 原生 axios 其他封装
自动 token 处理 部分支持
重复请求取消 需手动实现 部分支持
多状态码支持
TypeScript 支持 部分支持
配置灵活性 一般
学习成本

🎯 未来规划

  1. 请求缓存机制 - 支持 GET 请求缓存,避免重复请求相同数据
  2. 请求重试机制 - 网络异常时自动重试
  3. 请求队列管理 - 控制并发请求数量
  4. 更多适配器 - 支持更多平台(React Native、Electron 等)

📝 总结

request-fruge365 是一个轻量级但功能强大的 HTTP 请求工具,它解决了日常开发中的常见痛点:

  • 开箱即用:无需复杂配置,安装即可使用
  • 功能完整:token 管理、重复请求取消、错误处理一应俱全
  • 高度灵活:支持各种自定义配置,适应不同项目需求
  • 类型安全:完整的 TypeScript 支持
  • 生产就绪:经过实际项目验证,稳定可靠

如果你也在为 HTTP 请求的各种问题而烦恼,不妨试试这个工具。相信它能让你的开发体验更加愉快!

🔗 相关链接


如果这个工具对你有帮助,欢迎给个 ⭐ Star 支持一下!也欢迎提 Issue 和 PR,一起让它变得更好!


网站公告

今日签到

点亮在社区的每一天
去签到