axios-plugins: 用最小的侵入性, 为 axios 扩展更多的插件能力

前言

来厚着脸皮推荐下新写的插件库 axios-plugins, 这可能是今年以来, 你能看到的对请求工具的扩展中, 对原项目影响最小、学习成本最低、插件额比较丰富的工具库了.

尝鲜使用, 可直接跳转下面的使用篇

推荐理由

  • 改造成本

现阶段, 关于请求工具能力扩展的插件有几类:

  • 完全实现, 实现完整的请求工具及扩展能力, 如: ahooks
  • 包装请求工具(axios, fetch)的实现, 并提供自己的api, 如: alova
  • 通过原生api扩展, 如: axios-retry, axios-extensions

上面几种方式使用起来各有优略,相比与前两种方式来说, 第三种对于存量项目来说更加友好。 axios-plugins就是沿着这个思路实现的, 并尽可能地降低使用插件对现有项目地改动.

先放一段简单的插件代码勾引一下~

import axios from 'axios'

import { useAxiosPlugin, mock, loading } from 'axios-plugins'

const request = axios.create({  })

request.interceptors.request.use() // 如果有拦截器, 原有的拦截器不受影响

// Tips: 一般情况下, 使用插件仅需要添加这一段代码即可. 主打的就是一个低侵入
useAxiosPlugin(request)
    .plugin(mock({ mockUrl: 'http://mock' }))
    .plugin(loading({
        onTrigger: (show) => {} // TODO 实现loading组件切换逻辑
    }))


// 如果你需要使用 request({ ... }) 方式发起请求, 需要简单改动下
export const request2 = useAxiosPlugin(request).wrap()
  • 代码体积

    • 核心包体积(1.37kb/gziped)
    • 完整包体积(5.88kb/gziped) | ps: 后续可能会因为插件增多而增大

核心逻辑不到 1.5kb, 支持 TreeShaking 和 单插件引用。相比于扩展的能力来说, 这点代码量还算凑合. 当然, 受限于个人能力、兼容更多场景的因素, 现有代码还有优化空间, 实际使用中, 可以根据需要, 重新实现插件逻辑来提高代码性能.

对于使用 vitejs 构建的项目来说, 直接使用即可. 如果是webpack构建的项目, 可能需要根据配置, 调整使用单插件引用方式来降低代码体积.

  • 稳定性

目前是第一版, 核心的 useAxiosPlugin()IPlugin 接口已经固定, 相关的单元测试已经全覆盖了. 这部分理论上来说, 后续是不会去动这块内容了(除非有一些优化想法, 会去做一些小改动, 但不会去影响API设计)

插件部分, 单元测试目前还没有完成, 当然了, 因为刚把核心能力实现完的因素, 这一部分还需要慢慢打磨, 如果在使用过程中遇到了问题, 欢迎向我提 ISSUE

  • 丰富地插件能力

目前吧, 我已经实现了17个插件(虽然单元测试还没写完~), 具体可以参考下面的 插件列表

使用篇

文档地址: axios-plugins

安装依赖

yarn add axios axios-plugins 
// or
npm install axios axios-plugins 

配置插件

import axios from 'axios'

// 默认导出
import { useAxiosPlugin, loading } from 'axios-plugins'

// 按需引用方式 (与默认导出二选一, 如果使用的是vite一类的支持TreeShakin的编译器, 直接使用默认导出即可)
import { useAxiosPlugin } from 'axios-plugins/core'
import { loading } from 'axios-plugins/plugins/loading'


// 1. 定义axios实例 或 使用项目现有的axios实例
export const request = axios.create({
    /* ... */
})


// 2. 添加插件
useAxiosPlugin(request).plugin(loading())

// 3. 请求中使用 (参考插件使用)
request.post('/api', {}, { loading: false }) // 请求时参数通过 `AxiosRequestConfig` 扩展, 不需要特殊的使用方式

插件列表

plugin 名称 描述
debounce 防抖 在一段时间内发起的重复请求, 后执行的请求将等待上次请求完成后再执行
throttle 节流 在一段时间内发起的重复请求, 后执行的请求将被抛弃
merge 重复请求合并 在一段时间内发起的重复请求, 仅请求一次, 并将请求结果分别返回给不同的发起者
retry 失败重试 当请求失败(出错)后, 重试 n 次, 当全部失败时, 再抛出异常
cancel 取消(中止)请求 提供 cancelAll() 方法, 中止当前在进行的所有请求
transform 转换请求/响应 替代axios.interceptors的使用, 用于统一管理 axios 请求过程
cache 响应缓存 存储请求响应内容, 在下次请求时返回 (需要在缓存时效内)
envs 多环境配置 规范化 axios 多环境配置工具
mock 模拟(调试用) 提供全局或单个接口请求 mock 能力
normalize 参数规范化 过滤请求过程中产生的 undefined, null 等参数
pathParams 路由参数处理 扩展对 Restful API 规范的路由参数支持
sign 参数签名 提供请求防篡改能力, 这个功能需要搭配后端逻辑实现
loading 全局 loading 提供全局 loading 统一控制能力, 减少每个加载方法都需要独立 loading 控制的工作量
logger 日志 自定义请求过程日志打印
sentryCapture sentry 错误上报 提供 sentry 捕获请求异常并上报的简单实现.
onlySend 仅发送 提供 navigator.sendBeacon 方法封装, 实现页面离开时的埋点数据提交, 但这个需要后端支持
mp 小程序请求适配器 扩展对小程序(微信、头条、qq 等)、跨平台框架(uni-app, taro)网络请求的支持

FAQ

写这个插件的原因

起初是这样的前端时间受 alova 的影响, 想着也搞个请求类扩展插件丰富下工具库. 简单实验了下, 本来计划参考axios-extensions 实现方式通过 adapter 扩展能力, 发现有些事情通过这个做比较麻烦, 就换了下实现方式, 通过上层包装实现. 就改了名字, 改成 axios-plugins 后, 诶,这名字还没被占用 , . 在看到不少人下载后, 被迫在两周内把这个插件库实现并更新上去~

实现原理

ps: 图画的不好, 简单理解下

image.png

原理上就是包装 axios 实例内的 request 方法, 在方法执行前后触发相关钩子实现插件效果.

由于 axios.create() 创建的实例需要支持 axios() 方式调用, 所以 axios 实际导出的是一个 function wrap() 包装函数, 如果直接在上面修改, 仅能够对 axios.request 产生效果, 对其他方法不起效. 所以, 这里通过两个步骤的组合, 来覆盖 axios.request 的实现

  • new 一个新的扩展实例并集成现有实例属性.
  • 通过 Object.defineProperties 将原实例的方法映射到新实例上面.

大概就是这个思路, 结合上面的操作和 axios.interceptors, 我们可以获取到 axios 触发请求的几个节点

  • before: 插件注册时
  • pre: 请求实际发起前 (request() 调用前)
  • axios.interceptors.request 请求拦截器
  • axios.interceptors.response响应拦截器 (遵循原有的use导入触发时机)
  • post:请求结束后(可以拿到响应和捕获到执行过程异常)

由于interceptors 受前置拦截器的影响以及可能会因为请求失败不执行导致 完整的插件过程无法被触发。所以, 实际使用时, 仅针对需要修改发起请求的参数内容在 axios.interceptors.request 中进行修改, 响应则在axios请求完成(包含抛出异常)后, 进行处理.

然后呢, 就有了如下几个钩子:

  • (在 axios.request 调用前触发钩子) preRequestTransform
  • (axios.interceptors.request 钩子) transformRequest
  • (响应后触发钩子) postResponseTransform
  • (捕获异常钩子) captureException
  • (请求完成后置钩子) completed

大概原理上就是这个样子

插件执行顺序

遵循先进后出原则

|- plug 1
|- plug 2
    |- request
|- plug 2
|- plug 1

写在最后

搞点开源的东西不容易, 如果这个插件能对您产生一些帮助, 麻烦给我的项目 点一下 star, 谢谢 ~

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYr3k5WQ' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片