前言
来厚着脸皮推荐下新写的插件库 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: 图画的不好, 简单理解下
原理上就是包装 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, 谢谢 ~