一款注解驱动的axios工具

Awe-Axios

注意以下只是简介,具体参考官方文档。 Official website 中文官网

基本介绍

Awe-Axios 是基于 axios 扩展的增强型 HTTP 请求工具库,通过装饰器模式、配置扩展等方式优化请求体验,同时保持与 axios 生态的完全兼容。支持注解驱动、请求重传、防抖节流、Mock 拦截、面向切面、依赖注入等核心功能,适用于各类前端 HTTP 请求场景。

核心特性

  • 注解驱动:通过装饰器定义 API 接口,被装饰方法自动代理为请求接口,简化配置
  • 功能封装:内置请求重传、防抖、节流等常用功能,无需重复开发
  • 无侵入设计:不修改 axios 原有 API,兼容现有 axios 项目
  • 真实 Mock 拦截:基于 msw 实现网络层面请求拦截,支持接口二义性(同一接口既是真实接口也是 Mock 接口)
  • 面向切面(AOP):支持请求前后、成功失败等阶段的精细化拦截
  • 依赖注入(DI):提供 IoC 容器,支持类实例注册与注入,解耦组件依赖
  • 多环境适配:支持自定义 axios 实例,适配不同域名、认证方式的后端服务

适用场景

  1. 企业级应用开发:通过装饰器集中管理 API,提升代码可维护性
  2. 高频请求场景:防抖、节流功能减少无效网络请求,优化性能
  3. 不稳定网络环境:请求重传机制提升接口成功率
  4. 前后端并行开发:内置 Mock 功能,无需等待后端接口就绪
  5. 多环境切换:支持自定义 axios 实例,适配开发、测试、生产等多环境
  6. 数据转换需求:提供请求/响应数据转换器,处理格式转换、加密解密等场景

快速开始

安装

bash 复制代码
# npm
npm install awe-axios --save

# yarn
yarn add awe-axios

环境要求

需使用 TypeScript 开发,在 tsconfig.json 中添加以下配置:

json 复制代码
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

基本使用

typescript 复制代码
import { HttpApi, Get, Post, PathParam, BodyParam, QueryParam } from 'awe-axios';

@HttpApi({
  baseURL: 'http://localhost:3000/users',
})
class UserApi {
  // GET /users
  @Get('/')
  getAllUsers(): any {}

  // GET /users/:id (失败时重试3次)
  @Get({
    url: '/:id',
    retry: 3,
  })
  getUserById(@PathParam('id') id: number): any {}

  // POST /users (提交请求体)
  @Post('/')
  addUser(@BodyParam() data: { name: string; age: number }): any {}

  // GET /users/page?page=xxx&size=xxx (Mock 接口)
  @Get({
    url: '/page',
    mock: {
      handlers: () => {
        return HttpResponse.json({
          data: [1, 2, 3],
          total: 3,
        });
      },
    },
  })
  getPage(@QueryParam('page') page: number, @QueryParam('size') size: number): any {}
}

// 使用示例
const userApi = new UserApi();
const allUsers = await userApi.getAllUsers();
const user = await userApi.getUserById(1);
const newUser = await userApi.addUser({ name: 'test', age: 18 });

原生 axios 使用

AxiosPlus 兼容原生 axios API,可直接使用 axiosPlus 调用:

typescript 复制代码
import { axiosPlus } from 'awe-axios';

// 请求拦截器
axiosPlus.interceptors.request.use(config => {
  console.log('请求拦截器', config);
  return config;
});

// 直接发起请求
axiosPlus.get('http://localhost:3000/users');

HTTP 请求方法

AxiosPlus 提供类装饰器和方法装饰器,用于快速定义 API 接口。

类装饰器 @HttpApi

用于标记 HTTP 接口类,定义公共配置:

typescript 复制代码
import { HttpApi, Get } from 'awe-axios';

// 基础用法
@HttpApi('https://api.example.com')
class UserApi {
  @Get('/users')
  getUserList(): any {} // 实际请求地址:https://api.example.com/users
}

// 完整配置
@HttpApi({
  baseURL: 'https://api.example.com', // 基础路径
  url: '/v1', // 路径前缀
  refAxios: customAxiosInstance, // 自定义 axios 实例
  mock: {
    // 全局 Mock 配置
    on: true, // 是否开启 Mock
    condition: () => process.env.NODE_ENV === 'development', // 触发条件
  },
})
class UserApiV1 {
  @Get('/users')
  getUserList(): any {} // 实际请求地址:https://api.example.com/v1/users
}
配置合并规则
  • baseURL:方法装饰器配置覆盖类装饰器
  • url:类装饰器 url 与方法装饰器 url 自动拼接(处理斜杠)
  • headers:深度合并,方法装饰器配置优先
  • refAxios:方法装饰器配置覆盖类装饰器

方法装饰器

涵盖所有 HTTP 标准方法,配置项继承自 axios 并扩展增强功能:

装饰器 说明 适用场景
@Get 定义 GET 请求 查询资源
@Post 定义 POST 请求 创建资源(注意幂等性)
@Put 定义 PUT 请求 全量更新资源
@Delete 定义 DELETE 请求 删除资源
@Patch 定义 PATCH 请求 部分更新资源
@Options 定义 OPTIONS 请求 跨域预检、查询支持的方法
@Head 定义 HEAD 请求 获取响应头(无响应体)
示例:@Post 用法
typescript 复制代码
@HttpApi('https://api.example.com')
class UserApi {
  @Post('/users')
  createUser(@BodyParam() user: { name: string; age: number }) {}
}
增强功能配置

方法装饰器支持重试、防抖、节流等增强配置:

typescript 复制代码
@Get({
  url: '/data',
  retry: 3, // 重试3次
  debounce: 300, // 防抖300ms
  throttle: 1000, // 节流1s
  mock: {} // Mock 配置
})
getData(): any {}

参数装饰器

用于处理请求参数,支持查询参数、路径参数、请求体参数:

@QueryParam

将参数转换为查询字符串(?key=value):

typescript 复制代码
@HttpApi('http://localhost:3000/users')
class UserApi {
  @Get('/pages')
  getUserPages(@QueryParam('page') page: number, @QueryParam('size') size: number): any {}
}

// 调用:userApi.getUserPages(1, 20)
// 最终地址:http://localhost:3000/users/pages?page=1&size=20
多参数合并

同名参数自动合并为数组:

typescript 复制代码
@Get('/groups')
getUserGroups(
  @QueryParam('ids') id1: number,
  @QueryParam('ids') id2: number
): any {}

// 调用:userApi.getUserGroups(1, 2)
// 最终地址:http://localhost:3000/users/groups?ids[]=1&ids[]=2

@PathParam

将参数替换为路径占位符(/path/:id):

typescript 复制代码
@Get('/:id')
getUserById(@PathParam('id') id: number): any {}

// 调用:userApi.getUserById(1)
// 最终地址:http://localhost:3000/users/1

@BodyParam

收集参数作为请求体(支持 JSON、form-data 等格式):

typescript 复制代码
// 基础用法
@Post('/')
createUser(@BodyParam() user: { name: string; age: number }): any {}

// 多参数合并
@Post('/')
createUser(
  @BodyParam('user') user: { name: string; age: number },
  @BodyParam('person') person: { sex: string }
): any {}
// 最终请求体:{ "user": { "name": "test" }, "person": { "sex": "男" } }

// 文件上传(需指定 Content-Type)
@Post({
  url: '/upload',
  headers: { 'Content-Type': 'multipart/form-data' }
})
uploadFile(@BodyParam('file') file: FormData): any {}

常用功能详解

请求重发(Retry)

请求失败时自动重试,提高成功率,适用于非实时性接口。

基本使用
typescript 复制代码
import { useRetry } from 'awe-axios';

// 定义接口
@HttpApi('http://localhost:3000/users')
class UserApi {
  @Get('/:id')
  getUserById(@PathParam('id') id: number): any {}
}

const userApi = new UserApi();
// 包装为带重试功能的接口
const retryGetUser = useRetry(userApi.getUserById);
// 调用(默认重试3次,基础延迟100ms)
await retryGetUser(1);
配置方式
typescript 复制代码
// 仅指定重试次数
const retryGetUser = useRetry(userApi.getUserById, 3);

// 完整配置
const retryGetUser = useRetry(userApi.getUserById, {
  count: 3, // 重试次数
  delay: 1000, // 基础延迟时间(ms)
});

// 数组形式 [次数, 延迟]
const retryGetUser = useRetry(userApi.getUserById, [3, 1000]);
特性
  • 指数退避策略:第 n 次重试延迟 = delay * 2^(n-1)
  • 首次重试无延迟,从第二次开始应用延迟
  • 不推荐 Post 请求使用(可能导致数据重复提交)

防抖(Debounce)

限制短时间内多次触发的请求,仅执行最后一次,适用于搜索框、频繁点击等场景。

基本使用
typescript 复制代码
import { useDebounce } from 'awe-axios';

// 包装为带防抖功能的接口
const debounceGetUser = useDebounce(userApi.getUserById, 300);

// 短时间内多次调用,仅执行最后一次
debounceGetUser(1);
debounceGetUser(2);
debounceGetUser(3); // 仅此次生效
配置方式
typescript 复制代码
// 仅指定延迟时间(ms)
const debounceGetUser = useDebounce(userApi.getUserById, 300);

// 完整配置
const debounceGetUser = useDebounce(userApi.getUserById, {
  delay: 300, // 延迟时间
  immediate: true, // 是否立即执行第一次请求
});

节流(Throttle)

限制请求执行频率,指定时间间隔内仅执行一次,适用于滚动加载、实时刷新等场景。

基本使用
typescript 复制代码
import { useThrottle } from 'awe-axios';

// 包装为带节流功能的接口(1s 内最多执行一次)
const throttleGetUser = useThrottle(userApi.getUserById, 1000);

// 短时间内多次调用,仅1s内首次生效
throttleGetUser(1);
throttleGetUser(2); // 被忽略
await delay(1000);
throttleGetUser(3); // 生效

功能组合

支持多种功能组合使用(装饰器模式):

typescript 复制代码
// 防抖 + 重试(搜索场景)
const debounceRetryGet = useDebounce(useRetry(userApi.getUserById), 300);

// 节流 + 重试(滚动加载场景)
const throttleRetryGet = useThrottle(useRetry(userApi.getUserById), 1000);
注意事项
  • 不推荐防抖与节流同时使用(策略冲突)
  • 推荐组合:搜索场景(防抖+重试)、滚动加载(节流+重试)、普通接口(仅重试)

子项装饰器

用于拆分复杂配置,使代码结构更清晰,支持以下子项装饰器:

@RefAxios(类装饰器)

设置类中所有接口的默认 axios 实例:

typescript 复制代码
const customAxios = axiosPlus.create({ baseURL: 'http://localhost:3000/users' });

@HttpApi()
@RefAxios(customAxios)
class UserApi {
  @Get('/pages')
  getUserPages(): any {} // 自动使用 customAxios 实例
}

@AxiosRef(方法装饰器)

设置单个接口的 axios 实例(优先级高于类配置):

typescript 复制代码
class UserApi {
  @Get('/pages')
  @AxiosRef(customAxios)
  getUserPages(): any {}
}

@TransformResponse

设置响应数据处理器(与 axios transformResponse 一致):

typescript 复制代码
@Get('/pages')
@TransformResponse([
  // 第一步:解析 JSON 并提取 data 字段
  data => JSON.parse(data).data,
  // 第二步:处理数据
  data => data.map(user => ({ ...user, age: 18 }))
])
getUserPages(): any {}

@TransformRequest

设置请求数据处理器(与 axios transformRequest 一致):

typescript 复制代码
@Post('/')
@TransformRequest([
  // 第一步:添加额外字段
  data => ({ ...data, sex: '男' }),
  // 第二步:转换为 JSON 字符串
  data => JSON.stringify(data)
])
createUser(@BodyParam() user: { name: string; age: number }): any {}

Mock 接口搭建

基于 msw 实现网络层面请求拦截,支持接口二义性(同一接口既是真实接口也是 Mock 接口)。

基本使用

typescript 复制代码
import { MockAPI, HttpResponse } from 'awe-axios';

// 开启全局 Mock
MockAPI.on();

@HttpApi('http://localhost:3000/users')
class UserApi {
  @Get({
    mock: ctx => {
      return HttpResponse.json({
        data: [
          { id: 1, name: 'Alice' },
          { id: 2, name: 'Bob' },
        ],
      });
    },
  })
  getUsers(): any {}
}

// 调用 Mock 接口(柯里化调用)
const userApi = new UserApi();
const { data } = await userApi.getUsers()();

处理器函数

支持多状态处理器(成功/失败等):

typescript 复制代码
@Get({
  mock: {
    handlers: {
      success: ctx => HttpResponse.json({ data: [1, 2, 3] }),
      error: ctx => HttpResponse.error()
    }
  }
})
getUsers(): any {}

// 调用指定处理器
await userApi.getUsers()('success'); // 成功状态
await userApi.getUsers()('error'); // 失败状态
简化写法(mockHandlers)
typescript 复制代码
@Get({
  mockHandlers: {
    success: ctx => HttpResponse.json({ data: [1, 2, 3] }),
    error: ctx => HttpResponse.error()
  }
})
getUsers(): any {}

处理器参数

通过 ctx 参数获取请求信息:

typescript 复制代码
@Post('/pages/:page/:size')
@Mock({
  handlers: async ({ request, params, cookies }) => {
    // 获取查询参数
    const url = new URL(request.url);
    const page = url.searchParams.get('page');

    // 获取路径参数
    const { size } = params;

    // 获取请求体
    const body = await request.json();

    // 获取 Cookie
    const token = cookies.token;

    return HttpResponse.json({ page, size, body });
  }
})
getPages(): any {}

HttpResponse 常用方法

方法 说明 示例
json() 返回 JSON 格式响应(自动设置 Content-Type) HttpResponse.json({ data: [] }, { status: 200 })
error() 返回网络错误 HttpResponse.error()
text() 返回文本响应 HttpResponse.text('success')
html() 返回 HTML 响应 HttpResponse.html(' ## Hello ')

其它功能

请参见官网 Official website 中文官网

相关推荐
BLOOM3 小时前
新一代前端数据mock工具Data Faker
前端·javascript
UIUV3 小时前
微信小程序开发学习笔记:从架构到实战
前端·javascript·前端框架
程序猿_极客3 小时前
JavaScript的Web APIs 入门到实战(day2):事件监听与交互实现,轻松实现网页交互效果(附练习巩固)
开发语言·前端·javascript·学习笔记·web apis 入门到实战
Mintopia3 小时前
🚀 一文看懂 “Next.js 全栈 + 微服务 + GraphQL” 的整体样貌
前端·javascript·全栈
Mintopia3 小时前
🧬 医疗Web场景下,AIGC的辅助诊断技术边界与伦理
前端·javascript·aigc
半桶水专家4 小时前
父子组件通信详解
开发语言·前端·javascript
Watermelo6174 小时前
从vw/h到clamp(),前端响应式设计的痛点与进化
前端·javascript·css·算法·css3·用户界面·用户体验
Moment4 小时前
快到  2026  年了:为什么我们还在争论  CSS 和 Tailwind?
前端·javascript·css
梵得儿SHI4 小时前
Vue 核心语法详解:模板语法中的绑定表达式与过滤器(附 Vue3 替代方案)
前端·javascript·vue.js·插值语法·vue模板语法·绑定表达式·过滤器机制