搜索引擎不收录网站,网站建站哪个公司好一点,网站建设二次开发怎么样,网站改版 理论onion-middleware的由来
嗯。。。闲来无事瞎搞的#xff01;#xff01;#xff01;#xff01;主要用来实现请求/相应拦截#xff0c;当然队列性的数据操作都是可以的
直接上使用教程
安装
npm install onion-middleware使用
import { OnionMiddleware } from onion…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;// 4011401 重新静默登录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): PromiseT {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): PromiseT {return send(options);
};export default sendApi;
效果简单截个图吧拿请求/相应信息输出中间件为例效果如下 结尾
轻点喷