axios接口管理优化操作详解

作者:Chang爱学习 时间:2024-04-30 10:28:09 

强化功能

本文针对中大型的后台项目的接口模块优化,在不影响项目正常运行的前提下,增量更新。

  • 接口文件写法简化(接口模块半自动化生成)

  • 任务调度、Loading调度(接口层面的防抖兜底,多个接口共用一个loading,防止闪烁)

  • 接口提示自由化(提示消息可由前端控制,也可以由后端控制)

接口文件写法简化

对于一些中后台模块的接口,基本上都是增删改查以及审核流的一些功能(其他特殊接口暂且不谈)。如果后端接口足够规范的话,大概就是下面这个情形

import request from "@/utils/request";
// 销售退货列表
export function getSalesReturnList(data) {
 return request({
   url: "/sales_return/list",
   method: "post",
   data,
 });
}
// 保存销售退货
export function saveSalesReturn(data) {
 return request({
   url: "/sales_return/save",
   method: "post",
   data,
 });
}
// 根据Id获取销售退货
export function getSalesReturn(query) {
 return request({
   url: "/sales_return/get",
   method: "get",
   params: query,
 });
}
// 根据Id删除销售退货
export function deleteSalesReturn(data) {
 return request({
   url: "/sales_return/delete",
   method: "post",
   data,
 });
}
// 提交销售退货审核
export function submitSalesReturn(data) {
 return request({
   url: "/sales_return/submit",
   method: "post",
   data,
 });
}
// 审核销售退货
export function auditSalesReturn(data) {
 return request({
   url: "/sales_return/audit",
   method: "post",
   data,
 });
}
// 撤审销售退货
export function revokeAuditSalesReturn(data) {
 return request({
   url: "/sales_return/withdraw",
   method: "post",
   data,
 });
}
// 审核拒绝销售退货
export function rejectSalesReturn(data) {
 return request({
   url: "/sales_return/reject",
   method: "post",
   data,
 });
}
// 作废销售退货
export function discardSalesReturn(data) {
 return request({
   url: "/sales_return/discard",
   method: "post",
   data,
 });
}

我觉得这个也太重复了,而且接口函数命名太麻烦了,要让团队规范起来比较困难。能不能自动生成了,命名也帮忙处理了,这样这种接口文件岂不是更加规范。

接下来想想办法

假设如上,一个单据模块的通常来说有九个接口方法,增删改查,提交、作废、审核、撤审、拒绝。他们的 url,前面的 sales_return 拼接是固定的,不同的就是后面标识功能的路径标识。另外就是,method 分为 post 和 get 方法。

我们把这九个接口,看成是一个 9 位二进制上的 9 个位,1 代表存在,0 代表不存在。

我们可以创建一个 map 文件来做构建准备(如下)

export const apiEnum = {
 // 查列表  2^0
 1: {
   name: "list",//接口名称
   type: "post",//接口方式
 },
 // 查详情  2^1
 2: {
   name: "get",
   type: "get",
   loading: true,//是否需要loading调度、防抖
 },
 // 删列表 2^2
 4: {
   name: "delete",
   type: "post",
 },
 // 保存 或者 保存且提交  2^3
 8: {
   name: "save",
   type: "post",
   loading: true,
 },
 // 提交  2^4
 16: {
   name: "submit",
   type: "post",
   loading: true,
 },
 // 审核  2^5
 32: {
   name: "audit",
   type: "post",
 },
 // 撤审  2^6
 64: {
   name: "withdraw",
   type: "post",
 },
 // 拒绝  2^7
 128: {
   name: "reject",
   type: "post",
 },
 // 作废  2^7
 256: {
   name: "discard",
   type: "post",
 },
};
export const apiFuncModule = {
 // 全部
 COMMON: 511,
 // 增删改查
 CURD: 15,
};

当我传 1 的时候,九位为000000001,代表只有一个查接口。当我传 15 的时候,九位为000001111,代表拥有增删改查四个接口。以此类推。

接下就是完成处理函数,完成上面的功能(如下)

import request from "@/utils/request";
import { apiEnum, apiFuncModule } from "@/enum/baseModule/apiEnum";
function useApi(moduleName, code = 511) {
 let apiMap = {};
 for (let key in apiEnum) {
   if ((key & code) == key) {
     let obj = apiEnum[key];
  //可以按自己习惯来对接口函数命名
     let apiName = "api_" + obj.name;
     apiMap[apiName] = (data) => {
       return request({
         url: `/${moduleName}/${obj.name}`,
         method: obj.type,
         [obj.type == "get" ? "params" : "data"]: data,
         loading: obj.loading,
       });
     };
   }
 }
 return apiMap;
}
export { useApi, apiFuncModule as apiType };

完成以上步骤,我们的接口文件就可以这样写了,这样九个接口就写完了。而且一目了然,如需修改,只需要调整传参就行了。

import { useApi } from "@/utils/system/apiGenPlugin";
//code可以不传 ,默认为511
export const API = useApi("sales_return");
//若有其他特殊接口 兼容原始写法 互不影响
export function xxxxx(data) {
   ...
}

使用方式

//API集中管理
import { API as SalesReturn } from "@/api/workApi/sale/return";
const {api_save,api_delete,api_get,api_list,api_audit,api_withdraw,api_discard,api_submit,api_reject} = SalesReturn
//单独使用
import { useApi } from "@/utils/system/apiGenPlugin";
const {api_save,api_delete,api_get,api_list,api_audit,api_withdraw,api_discard,api_submit,api_reject} = useApi('sales_return')
  • 增 SalesReturn.api_save

  • 删 SalesReturn.api_delete

  • 改 SalesReturn.api_get

  • 查 SalesReturn.api_list

  • 审核 SalesReturn.api_audit

  • 撤审 SalesReturn.api_withdraw

  • 作废 SalesReturn.api_discard

  • 提交 SalesReturn.api_submit

  • 拒绝 SalesReturn.api_reject

任务调度、Loading调度

实际开发中,我们可能会有对接口调用做一些处理

  • 对提交事件进行防抖处理,防止重复提交。

  • 加载某些重要资源的时候,希望有个loading效果,来优化用户体验。

  • 让多个需要loading效果的接口,共用同一个loading,防止页面闪烁。

这些功能单独处理起来就显得很麻烦了,而且每个人的写法不一样,后期维护成本就更难。

废话不多说,直接贴代码

接口调度类

import { Loading } from "element-ui";
class RequestLock {
 // Loading 实例
 L_instance = null;
 // 接口map
 reqMap = new Map();
 // 最近一次调用接口时间戳
 timestamp = 0;
 constructor(timeout = 500) {
   // 过渡时间
   this.timeout = timeout;
 }
 // 创建任务
 put = (id) => {
   if (this.reqMap.has(id)) return false;
   this._put(id);
   return true;
 };
 _put = (id) => {
   this.timestamp = new Date().getTime();
   this.reqMap.set(id, true);
     //开启loading
   this.L_instance = Loading.service({
     fullscreen: true,
     background: "rgba(255, 255, 255, 0.1)",
     lock: true,
   });
 };
 // 移除任务
 del = (id) => {
   if (this.reqMap.has(id)) {
     this.reqMap.delete(id);
     if (this.reqMap.size == 0) {
       this._closeLoading();
     }
   }
 };
 // 清空所有的任务
 clearTask = () => {
   this.reqMap.clear();
   this.L_instance.close();
 };
   //平滑关闭loading
 _closeLoading = () => {
   let _timestamp = new Date().getTime();
   let settime = _timestamp - this.timestamp;
   if (settime > this.timeout) {
     this.L_instance?.close();
   } else {
     setTimeout(() => {
       this.L_instance?.close();
     }, this.timeout - settime);
   }
 };
}
export default RequestLock;

在axios里的使用

这个是增量优化,在不影响以前代码的条件下,添加功能

import { RequestLock } from "@/class/lock";
let loadLock = new RequestLock(500);
//请求拦截
service.interceptors.request.use(
 (config) => {
     ...
     //如果配置中有loading 开启调度
   if (config.loading) {
     if (!loadLock.put(config.url)) {
       return Promise.reject(new Error("repeat request!"));
     }
   }
     ...
   return config;
 },
 (error) => {
     ...
     //如果有错误请求,中止当前调度任务,并清空
   loadLock.clearTask();
     ...
   return Promise.reject(error);
 }
);
//响应拦截
service.interceptors.response.use(
 (response) => {
   ...
   //检查
   response.config.loading && loadLock.del(response.config.url);
   ...
 },
 (error) => {
   loadLock.clearTask();
   return Promise.reject(error);
 }
);

接口文件书写

// 根据Id获取销售退货
export function getSalesReturn(query) {
 return request({
   url: "/sales_return/get",
   method: "get",
   params: query,
   //在这里配置loading为true,开启
   loading:true
 });
}

提示信息自由化

有时候当我删除一条数据,需要有个弹框提示删除是否成功。通常我们会在接口成功回调的时候加上这个功能。需要判断状态,来显示提示框的描述和颜色。另一方面,有时候删除一条数据,业务需求提示不单单是简单的“删除成功!”,还可能需要其他的附加提示。比如“删除单据xxx成功,请及时处理xxxx!”。这种需求没什么难度,但是有沟通成本和维护成本。业务有一些变化就需要修改。

另一方面,后端对系统的业务逻辑更加贴近,提示功能交给后端更加合理。当然,前端也需要保留这个功能,去兼容某些需求。

import { Message } from "element-ui";
export function responseMsgHandle(res) {
   //这里需要后端响应数据格式的配合,MsgType表示提示状态,Msg表示提示描述
 let { MsgType, Msg } = res;
 if (["success", "warning", "error"].includes(MsgType)) {
   Message({
     message: Msg,
     type: MsgType,
     duration: 5 * 1000,
   });
 }
}

使用

import { responseMsgHandle } from "@/utils";
//响应拦截
service.interceptors.response.use(
 (response) => {
   ...
   const res = response.data;
   responseMsgHandle(res);
   ...
 },
 (error) => {
     ...
   responseMsgHandle({
       MsgType:"error",
       Msg:error.message,
   });
     ...
   return Promise.reject(error);
 }
);

来源:https://juejin.cn/post/7176879447830691901

标签:axios,接口管理,优化
0
投稿

猜你喜欢

  • VMWare linux mysql 5.7.13安装配置教程

    2024-01-14 04:17:43
  • 深入学习Golang并发编程必备利器之sync.Cond类型

    2024-05-09 14:58:34
  • 微信小程序滑动选择器的实现代码

    2024-05-09 10:34:48
  • MySQL RC事务隔离的实现原理

    2024-01-29 06:12:23
  • JavaScript动态调整图片尺寸

    2009-11-23 12:20:00
  • MySQL修改默认字符集

    2010-11-02 12:11:00
  • 详解python程序中的多任务

    2021-01-10 18:55:37
  • python3.x上post发送json数据

    2021-07-03 02:07:23
  • 好习惯和坏习惯

    2009-01-20 12:51:00
  • Python随机数用法实例详解【基于random模块】

    2023-10-26 08:48:49
  • python 如何快速复制序列

    2022-12-04 05:20:36
  • 解决新版Pycharm中Matplotlib图像不在弹出独立的显示窗口问题

    2023-06-28 02:44:14
  • 一文读懂JS中的var/let/const和暂时性死区

    2024-04-19 10:06:05
  • Python实现图像手绘效果的方法详解

    2021-10-27 08:22:23
  • python3 简单实现组合设计模式

    2023-06-12 19:15:50
  • php字符串函数 str类常见用法示例

    2024-05-11 10:01:43
  • Python学习笔记之Zip和Enumerate用法实例分析

    2021-09-03 19:58:50
  • php5.4以下版本json不支持不转义内容中文的解决方法

    2023-07-02 17:10:45
  • Python利用VideoCapture读取视频或摄像头并进行保存

    2022-12-06 18:26:27
  • 如何由Sybase向SQL Server移植数据库

    2009-01-20 15:56:00
  • asp之家 网络编程 m.aspxhome.com