axios的替代方案onion-middleware
onion-middleware的由来
嗯。。。闲来无事瞎搞的!!!!主要用来实现请求/相应拦截,当然队列性的数据操作都是可以的
直接上使用教程
- 安装
npm install onion-middleware
- 使用
import { OnionMiddleware } from 'onion-middleware'// vite等模块化加载的工具需调用clearMiddleware
app.clearMiddleware()// 创建一个中间件应用
const app = new OnionMiddleware()// 添加中间件
app.use(async (ctx, next) => {// Middleware Before to do somethingnext()// Middleware After to do something
})
- 实战使用
import { BaseResponse, CtxType, FetchOptionsType } from './type';
import storage from '../storage';
import { sortObject } from '../common';
import { aesDecrypt, aesEncrypt } from './cryproUtil';
import config from '@/configs/config';
import { message } from 'antd';
import { OnionMiddleware } from 'onion-middleware'
const pendingPromises: { [key: string]: any } = {};
export const fetchApi = (options: FetchOptionsType) => {const { url, timeout, headers, method, data = {}, ...args } = options || {};const queryData =data instanceof FormData ? data : JSON.parse(JSON.stringify(data)); // 去掉undefined的属性值let conpleteUrl = url;const reqOptions = { ...args, headers, method };if (['GET', 'DELETE'].includes(method?.toUpperCase())) {conpleteUrl = url + '?';for (let key in queryData) {const val = queryData[key]conpleteUrl += `${key}=${typeof val === 'object' ? JSON.stringify(val) : encodeURIComponent(queryData[key])}&`;}} else {reqOptions.body =typeof queryData === 'string' || queryData instanceof FormData? queryData: JSON.stringify(queryData);if (queryData instanceof FormData) {delete reqOptions.headers['Content-Type'];}}return Promise.race([fetch(conpleteUrl, reqOptions).then((response) => {return response.json();}).catch((e) => {return JSON.stringify({code: 504,msg: '连接不到服务器',});}),new Promise((_, reject) =>setTimeout(() => reject(new Error('Request timeout')), timeout)),]);
};const app = new OnionMiddleware()
app.clearMiddleware();// 特殊业务处理中间件(401),以及相应数据的ts类型定义
app.use(async (ctx: CtxType, next: (arg?: any) => void) => {// Middleware Beforeawait next();// Middleware Afterconst { response } = ctx;// 401,1401 重新静默登录if ([401, 1401].includes(response?.code)) {// 未登录storage.clearAll();message.error('登录过期,请重新登陆!');// to do something}
});// 重复请求复用中间件
app.use(async (ctx: CtxType, next: (arg?: any) => void) => {// Middleware Beforeconst { request } = ctx;// 使用请求信息作为唯一的请求key,缓存正在请求的promise对象// 相同key的请求将复用promiseconst requestKey = JSON.stringify([request.method.toUpperCase(),sortObject(request.data),]);if (pendingPromises[requestKey]) {console.log('重复请求,已合并请求并返回共享的第一次请求,参数:', request);await next({shouldAbort: true,callback: () => {return pendingPromises[requestKey];},});} else {await next();}// Middleware Afterdelete pendingPromises[requestKey];
});// 请求/相应信息输出中间件
app.use(async (ctx: CtxType, next: (arg?: any) => void) => {// Middleware Beforeawait next();// Middleware Afterconst { request, response } = ctx;if (request?.errorTip && ![200, 401, 1401].includes(response.code)) {message.error(response.msg);}console.log('请求参数', {url: request?.url,data: request?.originData,method: request?.method,});console.log('响应参数', response);
});// header处理中间件(此中间件位于)
app.use(async (ctx: CtxType, next: (arg?: any) => void) => {// Middleware Beforeconst { request, response } = ctx;const token = storage.getItem('token');if (token) {// 请求头token信息,请根据实际情况进行修改request.headers['Authorization'] = 'Bearer ' + token;}ctx.request = request;await next();// Middleware After
});// 加解密
app.use(async (ctx: CtxType, next: (arg?: any) => void) => {// Middleware Beforeconst { request } = ctx;request.originData = request.data;if (config.OPEN_ENCRYPTION) {const aesData = aesEncrypt(request.data);// 加密request.data = { encryptedReqData: aesData[0] };// signrequest.headers['sign'] = aesData[1];}await next();// Middleware Afterif (config.OPEN_ENCRYPTION) {if (ctx.response?.encryptedResData) {ctx.response = aesDecrypt(ctx.response?.encryptedResData || '') || '{}';}}
});// 公共请求发送方法(简约)
const send = <T>(options: any): Promise<T> => {const { errorTip = true } = options;// HTTP请求上下文const ctx: CtxType = {request: {...options,errorTip,config: {timeout: 60 * 1000,baseUrl: config.VITE_API_URL + config.VITE_BASE_URL,},headers: {'Content-Type': 'application/json',},},promise: { resolve: () => { }, reject: () => { } },};const baseRequest = new Promise((resolve: (arg: T) => void, reject) => {// 打破promise回调作用域,在其他地方实现调用ctx.promise.resolve = resolve;ctx.promise.reject = reject;// 执行中间件app.execute(ctx, () => {let { config } = ctx?.request || {};const { data, method, url, headers } = ctx?.request || {};const fetchPromise = new Promise(async (_resolve) => {config = {...config,data,headers,url: config.baseUrl + (url || ''),method: method.toUpperCase(), // 配置method方法};const res = await fetchApi({...options,...config,});_resolve(res);});return fetchPromise;}).then(() => { }).catch((err) => {console.log(err);});});// 使用请求信息作为唯一的请求key,缓存正在请求的promise对象// 相同key的请求将复用promiseconst requestKey = JSON.stringify([options.method.toUpperCase(),options.url,sortObject(options.data),]);// 存储第一次请求引用 (重复请求判断需要)if (!pendingPromises[requestKey]) {pendingPromises[requestKey] = baseRequest;}return baseRequest;
};// 公共请求发送方法
const sendApi = <T = BaseResponse>(options: FetchOptionsType): Promise<T> => {return send(options);
};export default sendApi;
效果简单截个图吧,拿请求/相应信息输出中间件为例,效果如下:

结尾
轻点喷😂😂😂
相关文章:
axios的替代方案onion-middleware
onion-middleware的由来 嗯。。。闲来无事瞎搞的!!!!主要用来实现请求/相应拦截,当然队列性的数据操作都是可以的 直接上使用教程 安装 npm install onion-middleware使用 import { OnionMiddleware } from onion…...
设计模式——泛型单例类
游戏中很多管理类都需要写成单例类,每次重复把管理类设置为单例类很繁琐, 这里直接写一个泛型单例类作为模板父类,方便其他需要写成单例类的类直接继承设置为单例类; using UnityEngine;public class Singleton<T> : Mono…...
三维卷积( 3D CNN)
三维卷积( 3D CNN) 1.什么是三维卷积 1.1 三维卷积简介 二维卷积是在单通道的一帧图像上进行滑窗操作,输入是高度H宽度W的二维矩阵。 三维卷积输入多了深度C这个维度,输入是高度H宽度W深度C的三维矩阵。在卷积神经网络中&…...
【JAVA】Java开发小游戏 - 简单的2D平台跳跃游戏 基本的2D平台跳跃游戏框架,适合初学者学习和理解Java游戏开发的基础概念
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默, 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……) 2、学会Oracle数据库入门到入土用法(创作中……) 3、手把…...
分享3个国内使用正版GPT的网站【亲测有效!2025最新】
1. molica 传送入口:https://ai-to.cn/url/?umolica 2. 多帮AI 传送入口:https://aigc.openaicloud.cn?inVitecodeMYAAGGKXVK 3. 厉害猫 传送入口:https://ai-to.cn/url/?ulihaimao...
CSDN Markdown编辑器设置视频居中完美解决方案
表格做中间容器,把视频放在表格里面,利用表格居中语法实现表格内元素居中对齐,从而完美实现视频居中。 【三角符文】jevil战无伤通关 这玩意整了我两个星期,焦头烂额都找不到解决方案。今天偶然想到可以用表格试试,没想…...
Java到底是值传递还是引用传递????
在搞懂这个问题之前, 我们要首先了解什么是值传递, 什么是引用传递? 值传递: 传递的是数据的副本,修改副本不会影响原始数据。引用传递: 传递的是数据的引用(地址),修改引用会直接影响原始数据. 也就是说,值传递和引…...
初学stm32 --- 电源监控
目录 STM32 电源监控介绍 上电/掉电复位POR/PDR(F1) 可编程电压检测器(PVD)(F1) PVD相关寄存器介绍(F1) 电源控制寄存器 PWR_CR 电源控制/状态寄存器 PWR_CSR PVD相关HAL库驱动介绍 PVD的使用步骤 …...
Win10本地部署大语言模型ChatGLM2-6B
鸣谢《ChatGLM2-6B|开源本地化语言模型》作者PhiltreX 作者显卡为英伟达4060 安装程序 打开CMD命令行,在D盘新建目录openai.wiki if not exist D:\openai.wiki mkdir D:\openai.wiki 强制切换工作路径为D盘的openai.wiki文件夹。 cd /d D:\openai.wik…...
[ LeetCode 75 ] 1768. 交替合并字符串
题目描述:(相关标签:双指针、字符串) 给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 返…...
(三)通过WebGL绘制一个简单的三角形来理解渲染管线
理解 WebGL 绘图原理的关键是了解它的渲染管线。WebGL 渲染管线实际上是由多个阶段组成的,每个阶段都有特定的任务,最终输出的是屏幕上的图像。为了让你能轻松理解这些原理,我将通过一个简单的例子来详细解释。 绘制一个简单的三角形 我们将…...
医学图像分析工具02:3D Slicer || 医学影像可视化与分析工具 支持第三方插件
3D Slicer 是一款功能全面的开源医学影像分析软件,广泛应用于影像处理、三维建模、影像配准和手术规划等领域。它支持多种医学影像格式(如 DICOM、NIfTI)和丰富的插件扩展,是神经科学、放射学和生物医学研究中不可或缺的工具。 在…...
Ollama VS LocalAI:本地大语言模型的深度对比与选择指南
随着人工智能技术的快速发展,大语言模型逐渐成为多个行业的重要工具。从生成内容到智能问答,大模型展现了强大的应用潜力。然而,云端模型的隐私性、使用成本和网络依赖等问题也促使更多用户关注本地化解决方案。Ollama 和 LocalAI 是近年来备…...
虚表 —— 隐藏行(简单版)
因为隐藏行改变了listview内部行号处理机制,需要处理大量细节,如listview内部用于传递行号的各种消息、通知等、封装的各种读取行号的函数等。 所以在工作量很大,一处纰漏可能导致重大bug的情况下,仅对隐藏行功能进行了简单封装&…...
CAD批量打印可检索的PDF文件
本文虽介绍CAD使用方法,但还是劝告大家尽早放弃使用CAD软件。。。。太TM难用了 当你打开CAD时发现如下一堆图纸,但是不想一个一个打印时。你可以按照下面操作实现自动识别图框实现批量打印。 1.安装批量打印插件 2.安装后打开CAD,输入命令Bp…...
2025.1.7(c++基础知识点)
作业(练习) 练习:要求在堆区连续申请5个int的大小空间用于存储5名学生的成绩,分别完成空间的申请、成绩的录入、升序排序、成绩输出函数以及空间释放函数,并在主程序中完成测试 要求使用new和delete完成 #include &…...
jenkins入门12-- 权限管理
Jenkins的权限管理 由于jenkins默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,我们使用Role-based Authorization Strategy 插件 只有项目读权限 只有某个项目执行权限...
Edge SCDN高效防护与智能加速
当今数字化时代,网络安全和内容分发效率已成为企业业务发展的关键因素。酷盾安全推出了Edge SCDN解决方案,为企业提供全方位的安全防护和高效的内容分发服务。 一、卓越的安全防护能力 1.DDoS攻击的精准防御:Edge SCDN具备强大的DDoS攻击检测…...
Ubuntu22.04配置静态ip
1. 编辑网络配置文件 sudo vim /etc/netplan/00-installer-config.yaml 2.输入下面配置 将静态ip设置为192.168.3.200 ,并设置路由器地址192.168.3.1,以及dns地址 223.5.5.5和223.6.6.6 dhcp4: false 表示取消动态分配ip network:ethernets:e…...
[Linux]线程的互斥与同步
目录 一、互斥 1.互斥的概念 2.互斥锁接口 3.线程加锁解锁本质 4.死锁 二、同步 1.同步的概念 2.条件变量 3.条件变量接口 一、互斥 1.互斥的概念 互斥指的是任何时刻,互斥保证有且只有一个执行流进入临界区,进行临界资源的访问,通…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
