之前我写了一篇文章,分享了自己的项目中对于接口管理的方法。总结下来就是:定义接口文件--withAxios导出--调用接口方法。这样实现了接口的统一管理和调用接口的语义化与简单化。

根据在项目的使用,发现有以下问题需要优化:

  1. withAxios导出的接口方法对象对编辑器来说是不透明的,所以代码提示功能缺失。
  2. 同一个方法调用多次,如何保证组件总是获取到最后一次的返回信息。

根据以上问题,采用了以下解决方案:

  1. 使用typescript的泛型解决。
  2. 调用同一个方法时,取消掉上次未完成的请求,这里使用axios的cancel方法。实现思路是在返回的方法对象中增加一个`${name}Cancel`的方法,保存取消上一次方法的回调,下次请求时固定调用这个取消方法以保证本次请求是当前唯一一个请求。(这里只提供axios层面的解决办法,不讨论其他办法,比如采用redux-saga的话可以使用takeLatest解决)

通过代码展示一下(React项目):

service.ts

import { IApiItem } from '@/configs/api/declares';
import withAxios from '@/utils/withAxios'; const api: IApiItem[] = [
{ name: 'getSummary', url: 'http://xx:8000/api/getSummary' },
{ name: 'getDetail', url: 'http://xx:8000/api/getDetail' },
{ name: 'getDetailChildren', url: 'http://xx:8000/api/getDetailChildren' },
{ name: 'getCurrentUser', url: 'http://xx:8000/api/getCurrentUser' },
]; interface IProdMonitorApi {
getSummary: any;
getDetail: any;
getDetailChildren: any;
getCurrentUser: any;
} export default withAxios<IProdMonitorApi>(api);

withAxios.ts

function withAxios<T>(apiConfig: IApiItem[], usePassportOrigin: boolean = false): T {
const serviceMap = {} as T;
apiConfig.map(({ name, url, method = 'get', ...rest }: IApiItem) => {
return (serviceMap[name] = async function(data = {}) {
if (serviceMap[`${name}Cancel`] && typeof serviceMap[`${name}Cancel`] === 'function') {
serviceMap[`${name}Cancel`]();
} const source = axios.CancelToken.source();
serviceMap[`${name}Cancel`] = () => {
source.cancel(`已取消上次未完成请求:${name}`);
};
rest.cancelToken = source.token; let key = 'params';
const apiMethod = method.toLowerCase();
if (apiMethod === 'post' || apiMethod === 'put') {
key = 'data';
}
let fetchUrl = url;
if (url.indexOf('http') !== 0) {
fetchUrl = usePassportOrigin
? NetworkUtils.passportOrigin + url
: NetworkUtils.serverOrigin + url;
}
return axios({
method,
url: fetchUrl,
[key]: data,
fetchName: name,
...rest,
} as AxiosRequestConfig);
});
});
return serviceMap;
} export default withAxios;

在需要使用接口的地方:

import Service from "./service.ts"

Service.getSummary(requestParams).then(...)

说明:

  1. 使用泛型虽然有了代码提示,但是额外增加了编码量,因为要手动维护一个方法接口,有利有弊吧,通过ts我还没有找到更好的方法。同事之前有过一个解决办法:接口管理使用对象的形式,然后withAxios修改这个对象各属性的getter,将getter指向通过axios包装后的方法,最终实现了本文相同的调用方式和代码提示,但这种方法有点hack的感觉。
  2. cancel掉上一个接口这种方式保证了数据总是来源于最后一个请求接口,但有时可能会出现问题,比如:在同一个页面需要展示两种用户:common用户和admin用户,后端给的接口是/api/v1/user,当参数type=1时为common,type=2时为admin,如果我们把这个接口定义为一个方法getUser,在这个页面会同时发出两个请求:Service.getUser({type:1}),Service.getUser({type:2}),但是,由于withAxios会取消上一个相同方法的请求,那么很可能有一个请求被取消,解决办法是在service中定义为两种方法:getCommonUser和getAdminUser,将type直接写入url中。这样也符合我们语义化的目标。

最新文章

  1. Python 调试 PDB
  2. 《zw版&#183;Halcon-delphi系列原创教程》简单的令人发指,只有10行代码的车牌识别脚本
  3. time模块学习
  4. 结构类模式(五):外观(Facade)
  5. modelsim remote
  6. js数组如何去掉逗号
  7. Java &amp; Android Interviews #1
  8. for、foreach和MoveNext循环效率粗比较
  9. 1QPushButton的使用,QLineEdit的使用,设置组件位置,布局(QHBoxLayout,QGridLayout)
  10. Spring MVC “404 Not Found”错误的解决
  11. Git仓库完全迁移,包括所有的分支和标签,当然也包括日志
  12. [Sw] 使用 Swoole Server task/协程 处理大数据量异步任务时注意
  13. PC timeline
  14. css学习_文本有关的样式属性、sublime快捷生成标签
  15. C++学习(三)(C语言部分)之 基本数据类型
  16. python之路——1
  17. vue回到顶部组件
  18. Javascript undefined 和 null
  19. 元素的定位tag_name,link_text,class_name
  20. CDN基础详解

热门文章

  1. SpringBoot整合log4j2进行日志配置及防坑指南
  2. Redis面试热点之底层实现篇(续)
  3. [TimLinux] Python 元类
  4. Python 入门必学经典知识点笔记【肯定有你不知道的】
  5. ARTS-S linux查看进程打开的文件数
  6. 在5分钟内将Spring Boot作为Windows服务启动
  7. 【系列专题】JavaScript 重温系列(22篇全)
  8. 重新精读《Java 编程思想》系列之组合与继承
  9. 大数据学习笔记——Hbase高可用+完全分布式完整部署教程
  10. docker入门-镜像管理命令篇