vue-axios-optimize 3.1.1 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -68
- package/index.js +1 -1
- package/package.json +4 -5
- package/types/index.d.ts +187 -0
- package/utils.js +1 -1
package/README.md
CHANGED
|
@@ -1,76 +1,24 @@
|
|
|
1
1
|
# vue-axios-optimize使用说明
|
|
2
2
|
|
|
3
3
|
vue-axios-optimize是一个对axios请求优化的vue插件包,引入此包之后,并进行相关配置,即可轻松实现全局请求加载动画,重复请求时取消前面的请求或者阻止后面的请求,并且可实现请求并发数量控制以及接口缓存。
|
|
4
|
-
[可阅读此文章 了解](https://www.xiaobu.host/vue-axios-optimize)
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+

|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
# npm
|
|
10
|
-
npm install vue-axios-optimize --save
|
|
11
|
-
# yarn
|
|
12
|
-
yarn add vue-axios-optimize --save
|
|
13
|
-
# pnpm
|
|
14
|
-
pnpm add vue-axios-optimize --save
|
|
15
|
-
```
|
|
7
|
+
详细阅读[官方使用文档](https://www.xiaobu.host/vue3-axios-optimize/)
|
|
16
8
|
|
|
17
|
-
##
|
|
9
|
+
## 微信公众号
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+

|
|
20
12
|
|
|
21
|
-
##
|
|
13
|
+
## 抖音号
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
api目录大致如下
|
|
26
|
-
|
|
27
|
-
> src
|
|
28
|
-
>
|
|
29
|
-
> > api
|
|
30
|
-
> >
|
|
31
|
-
> > > modules
|
|
32
|
-
> > >
|
|
33
|
-
> > > > common-api.js
|
|
34
|
-
> > >
|
|
35
|
-
> > > index.js
|
|
36
|
-
> > >
|
|
37
|
-
> > > axios.js
|
|
38
|
-
> > >
|
|
39
|
-
> > > axios-optimize.js
|
|
40
|
-
|
|
41
|
-
## new axiosOptimize(axios, instance, options)参数说明
|
|
42
|
-
|
|
43
|
-
| 参数 | 说明 | 来源 |
|
|
44
|
-
| -------- | ------------------------- | ------------------------------------- |
|
|
45
|
-
| axios | 安装axios中的axios | import axios from 'axios' |
|
|
46
|
-
| instance | 创建好的axios实例,已经配置好请求头等相关内容 | import instance from '@/api/axios.js' |
|
|
47
|
-
| options | 一些配置,详情继续阅读文档 | 自定义配置 |
|
|
48
|
-
|
|
49
|
-
## 特别注意
|
|
50
|
-
|
|
51
|
-
vue2项目的vue.config.js 需要添加如下配置,对插件包进行编译。
|
|
52
|
-
|
|
53
|
-
```js
|
|
54
|
-
module.exports = {
|
|
55
|
-
...
|
|
56
|
-
transpileDependencies: [
|
|
57
|
-
"vue-axios-optimize"
|
|
58
|
-
],
|
|
59
|
-
...
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## 总结
|
|
64
|
-
|
|
65
|
-
如有疑问,可关注微信公众号【爆米花小布】进行咨询。
|
|
66
|
-
|
|
67
|
-

|
|
15
|
+

|
|
68
16
|
|
|
69
17
|
## 打赏
|
|
70
18
|
|
|
71
19
|

|
|
72
20
|
|
|
73
|
-
微信公众号【爆米花小布】,抖音号【爆米花小布】
|
|
21
|
+
微信公众号【爆米花小布】,抖音号【爆米花小布】 更多好玩的插件
|
|
74
22
|
[vue2-element-dict字典包插件使用文档](https://www.xiaobu.host/vue2-element-dict/)
|
|
75
23
|
|
|
76
24
|
[vue2-element-dict字典包插件](https://www.npmjs.com/package/vue2-element-dict)
|
|
@@ -93,6 +41,15 @@ module.exports = {
|
|
|
93
41
|
|
|
94
42
|
## 更新日志
|
|
95
43
|
|
|
44
|
+
### 3.1.3
|
|
45
|
+
|
|
46
|
+
1. 【优化】完善 package.json 类型入口配置,修复 TS 类型无法正确加载问题
|
|
47
|
+
|
|
48
|
+
### 3.1.2
|
|
49
|
+
|
|
50
|
+
1. 【优化】】将超时重传默认时间从10秒改为60秒
|
|
51
|
+
2. 【优化】】`responseResultFun`配置新增第二个参数`config`,用于满足需要`config`做判断的需求
|
|
52
|
+
|
|
96
53
|
### 3.1.1
|
|
97
54
|
|
|
98
55
|
1. 【优化】`requestWithRetry`兼容下请求方法大小写
|
|
@@ -103,7 +60,7 @@ module.exports = {
|
|
|
103
60
|
|
|
104
61
|
1. 【优化】新增`abortAllRequests`中断所有请求的方法,用于切换路由时调用。
|
|
105
62
|
2. 【优化】新增`utils.js`文件,暴露`createCancelableRequest`,`requestWithRetry`方法,`createCancelableRequest`方法用于实现需要主动中断请求的接口,`requestWithRetry`方法用于实现需要超时重试的接口。
|
|
106
|
-
3. 【提示】`removeCache`这个方法很早就有,这个版本提示下吧
|
|
63
|
+
3. 【提示】`removeCache`这个方法很早就有,这个版本提示下吧 可以用于清除接口缓存的数据。
|
|
107
64
|
|
|
108
65
|
### 3.0.0
|
|
109
66
|
|
|
@@ -153,17 +110,17 @@ module.exports = {
|
|
|
153
110
|
|
|
154
111
|
### 2.0.1
|
|
155
112
|
|
|
156
|
-
1. 【功能】实现接口缓存配置
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
113
|
+
1. 【功能】实现接口缓存配置 options新增配置 cacheNum 配置最大缓存数量, 接口配置处可配置 cache: true。
|
|
114
|
+
注意:如下几种情况不建议配置缓存
|
|
115
|
+
1. 表单提交的接口
|
|
116
|
+
2. 数据频繁更新的接口
|
|
117
|
+
3. 删除数据接口
|
|
161
118
|
|
|
162
119
|
### 2.0.0
|
|
163
120
|
|
|
164
121
|
1. 【功能】实现并发请求数量控制,options新增maxReqNum参数配置 默认值为 4 ,表示同时可请求4个接口,剩余的接口陆续排队
|
|
165
|
-
2. 【优化】当接口返回数据格式为对象格式时,会多添加一个 IS_COMPLETE
|
|
166
|
-
3. 【调整】2.0.0版本 axios-optimize.js 文件不暴露 instance实例,且接口调用方法仅 支持 .get
|
|
122
|
+
2. 【优化】当接口返回数据格式为对象格式时,会多添加一个 IS_COMPLETE 表示当前全部请求任务是否已完成
|
|
123
|
+
3. 【调整】2.0.0版本 axios-optimize.js 文件不暴露 instance实例,且接口调用方法仅 支持 .get .post .delete .patch .put 形式调用, 具体查看文档示例
|
|
167
124
|
|
|
168
125
|
### 1.0.8
|
|
169
126
|
|
|
@@ -189,7 +146,7 @@ module.exports = {
|
|
|
189
146
|
|
|
190
147
|
### 1.0.1
|
|
191
148
|
|
|
192
|
-
1. 修复单词错误问题 isPervent 修改为
|
|
149
|
+
1. 修复单词错误问题 isPervent 修改为 isPrevent
|
|
193
150
|
|
|
194
151
|
### 1.0.0
|
|
195
152
|
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class e{axios;instance;requestConfigObj={};requestObj={};requestingNum=0;queue=[];isRefresh=!1;isShowReLoginDialog=!1;runningCount=0;maxReqNum=6;tasks=[];cache;cacheNum=10;status="start";runingReqKeys=[];showLoadingFun=()=>{};hideLoadingFun=()=>{};timeout=300;abortAllRequests(){Object.keys(this.requestObj).forEach((e=>{const t=this.requestObj[e],s=this.requestConfigObj[e];t.cancel(s)}))}abortRequestByConfig(e){const t=this.generateKeyByConfig(e);this.requestObj[t]&&(this.requestObj[t].cancel(e),delete this.requestObj[t],delete this.requestConfigObj[t])}add(e,t,s){return new Promise(((i,n)=>{try{if("pause"===this.status||"prevent"===s?.preventDuplicateRequestsType){if(this.tasks.some((e=>e.requestKey===t))||this.runingReqKeys.includes(t))return}if("cancel"===s?.preventDuplicateRequestsType){if(this.tasks.some((e=>e.requestKey===t))&&(this.tasks=this.tasks.filter((e=>e.requestKey!==t))),this.runingReqKeys.includes(t))return this.maxReqNum++,this.runingReqKeys.push(t),this.tasks.unshift({isCancel:!0,task:e,requestKey:t,config:s,resolve:i,reject:n}),void this._run()}this.runingReqKeys.push(t),this.tasks.push({task:e,requestKey:t,config:s,resolve:i,reject:n}),this._run()}catch(e){n(e)}}))}_pause(){this.status="pause"}_start(){this.status="start",this._run()}_run(){if("pause"!==this.status)for(;this.runningCount<this.maxReqNum&&this.tasks.length>0;){const{isCancel:e,task:t,requestKey:s,config:i,resolve:n,reject:r}=this.tasks.shift();e&&this.maxReqNum--,this.runningCount++,t().then((e=>{this.runningCount--,"[object Object]"===Object.prototype.toString.call(e)&&i?.showIsComplete?n({...e,[i.showIsComplete]:0===this.runningCount}):n(e)})).catch((e=>{if(this.runningCount--,!this.axios.isCancel(e)&&i?.removeRemainingTasksWhenError){const e=this.tasks.map((e=>e.requestKey));this.tasks=[],this.runingReqKeys=this.runingReqKeys.filter((t=>!e.includes(t)))}r(e)})).finally((()=>{this.runingReqKeys.splice(this.runingReqKeys.indexOf(s),1),this._run()}))}}getCache(e,t){const{url:s,data:i={},config:n,method:r}=t;return new Promise(((t,h)=>{if(!this.cache.has(e)){delete n.cache;return void(["get","delete"].includes(r)?this[r](s,n):this[r](s,i,n)).then((s=>{this.setCache(e,s),t(s)})).catch((e=>{h(e)}))}const a=this.cache.get(e);this.cache.delete(e),this.cache.set(e,a),n.noShowLoading?t(a):(this.showLoadingFun(),setTimeout((()=>{this.hideLoadingFun(),t(a)}),this.timeout))}))}setCache(e,t){if(this.cache.has(e)&&this.cache.delete(e),this.cache.set(e,t),this.cache.size>this.cacheNum){const e=this.cache.keys().next().value;this.cache.delete(e)}}removeCache(){this.cache&&this.cache.clear()}get(e,t){if(t.cache){const s={url:e,config:t,method:"get"},i=t.params,n=this.generateKey(s,i);return this.getCache(n,s)}const s=t.params;if(delete t.params,t.isRefreshToken)return this.instance.request({url:e,params:s,...t,method:"GET"});const i=t.fullPath?this.generateKey({url:e,method:"get"},s):"GET#"+e;return this.add((()=>this.instance.request({url:e,params:s,...t,method:"GET"})),i,t)}post(e,t={},s={}){if(s.cache){const i={url:e,data:t,config:s,method:"post"},n=this.generateKey(i,t);return this.getCache(n,i)}if(s.isRefreshToken)return this.instance.request({url:e,data:t,...s,method:"POST"});const i=s.fullPath?this.generateKey({url:e,method:"post"},t):"POST#"+e;return this.add((()=>this.instance.request({url:e,data:t,...s,method:"POST"})),i,s)}delete(e,t={}){if(t.cache){const s={url:e,config:t,method:"delete"},i=t.params||t.data||{},n=this.generateKey(s,i);return this.getCache(n,s)}if(t.params){const s=t?.params||{};if(delete t.params,t.isRefreshToken)return this.instance.request({url:e,params:s,...t,method:"DELETE"});const i=t.fullPath?this.generateKey({url:e,method:"delete"},s):"DELETE#"+e;return this.add((()=>this.instance.request({url:e,params:s,...t,method:"DELETE"},i,t)))}const s=t?.data||{};if(delete t.data,t.isRefreshToken)return this.instance.request({url:e,data:s,...t,method:"DELETE"});const i=t.fullPath?this.generateKey({url:e,method:"delete"},s):"DELETE#"+e;return this.add((()=>this.instance.request({url:e,data:s,...t,method:"DELETE"},i,t)))}patch(e,t={},s={}){if(s.cache){const i={url:e,data:t,config:s,method:"patch"},n=this.generateKey(i,t);return this.getCache(n,i)}if(s.isRefreshToken)return this.instance.request({url:e,data:t,...s,method:"PATCH"});const i=s.fullPath?this.generateKey({url:e,method:"patch"},t):"PATCH#"+e;return this.add((()=>this.instance.request({url:e,data:t,...s,method:"PATCH"},i,s)))}put(e,t={},s={}){if(s.cache){const i={url:e,data:t,config:s,method:"put"},n=this.generateKey(i,t);return this.getCache(n,i)}if(s.isRefreshToken)return this.instance.request({url:e,data:t,...s,method:"PUT"});const i=s.fullPath?this.generateKey({url:e,method:"put"},t):"PUT#"+e;return this.add((()=>this.instance.request({url:e,data:t,...s,method:"PUT"},i,s)))}generateKey(e,t){const{method:s,url:i}=e;let n=s+"#"+i;const r=[];for(const[e,s]of Object.entries(t))r.push(`${e}=${s}`);return r.length>0&&(n+="?"+r.join("&")),n}generateKeyByConfig(e){if(e.isRefreshToken||!e.fullPath)return e.url;const{url:t,method:s,data:i,params:n}=e;let r={};try{i&&Object.assign(r,JSON.parse(i))}catch{r={}}n&&Object.assign(r,n);const h={url:t,method:s};return this.generateKey(h,r)}constructor(e,t,s){this.axios=e;const i=s.code||"code",n=s.authorizationKey||"Authorization",r=s.responseTypesStr||"arraybuffer,blob",h=s.setAuthorizationFun||function(e,t){return e.headers[n]=t,e};s.showLoadingFun&&(this.showLoadingFun=s.showLoadingFun),s.hideLoadingFun&&(this.hideLoadingFun=s.hideLoadingFun),this.timeout=s?.timeout||this.timeout,this.maxReqNum=s?.maxReqNum||this.maxReqNum,this.cacheNum=s?.cacheNum||this.cacheNum,this.cache=new Map,this.instance=t,this.instance.interceptors.request.use((t=>{const s=this.generateKeyByConfig(t);t?.noShowLoading||(this.requestingNum++,this.showLoadingFun(t,this.requestingNum));t.url&&t.preventDuplicateRequestsType&&"cancel"===t.preventDuplicateRequestsType&&this.requestObj[s]&&this.requestObj[s].cancel({config:t});const i=e.CancelToken;return this.requestObj[s]=i.source(),t.cancelToken=this.requestObj[s].token,this.requestConfigObj[s]=t,t}),(e=>Promise.reject(e))),this.instance.interceptors.response.use((async e=>{const{config:t,responseErr:a}=e,u=this.generateKeyByConfig(t);if(t?.noShowLoading||(this.requestingNum--,this.requestingNum<=0&&(this.requestObj={},this.requestConfigObj={},this.hideLoadingFun(t,this.requestingNum))),t&&(this.requestObj[u]&&delete this.requestObj[u],this.requestConfigObj[u]&&delete this.requestConfigObj[u]),a){if(s.openRefresh){const r=s.accessTokenExpirationCode||401;if(Number(e[i])===r){this._pause();const i=s.getRefreshTokenFun();if(!i){if(this.isShowReLoginDialog)return;return this.isShowReLoginDialog=!0,this.removeCache(),s.reloginFun(e),Promise.reject(e||"Error")}if(this.isRefresh)return new Promise((e=>{this.queue.push((()=>{e(this.instance.request(t))}))}));this.isRefresh=!0;try{const e=t.headers[n],r=s.getAuthorizationFun();return e!==r?(this._start(),this.instance.request(h(t,r))):(await s.refreshTokenStore(i),this._start(),this.queue.forEach((e=>e())),this.instance.request(t))}catch{if(this.isShowReLoginDialog)return;return this.isShowReLoginDialog=!0,this.removeCache(),s.reloginFun(e),Promise.reject(e||"Error")}finally{this.queue=[],this.isRefresh=!1}}const a=s.refreshTokenExpirationCode||403;if(Number(e[i])===a){if(this.isShowReLoginDialog)return;return this.isShowReLoginDialog=!0,this.removeCache(),s.reloginFun(e),Promise.reject(e||"Error")}}return Promise.reject(e||"Error")}if(r.toLocaleLowerCase().split(",").includes(t?.responseType?.toLocaleLowerCase()))return e.data;const o=JSON.parse(JSON.stringify(e));return t.cache||delete o.responseErr,delete o.config,s.responseResultFun?s.responseResultFun(o):o}),(t=>{const i=t?.message?.config||{},n=this.generateKeyByConfig(i);return i?.noShowLoading||(this.requestingNum--,this.requestingNum<=0&&(this.requestObj={},this.requestConfigObj={},s.hideLoadingFun&&s.hideLoadingFun(i,this.requestingNum))),e.isCancel(t)||delete this.requestObj[n],delete this.requestConfigObj[n],Promise.reject(t)}))}}export default e;
|
|
1
|
+
class e{axios;instance;requestConfigObj={};requestObj={};requestingNum=0;queue=[];isRefresh=!1;isShowReLoginDialog=!1;runningCount=0;maxReqNum=6;tasks=[];cache;cacheNum=10;status="start";runingReqKeys=[];showLoadingFun=()=>{};hideLoadingFun=()=>{};timeout=300;abortAllRequests(){Object.keys(this.requestObj).forEach((e=>{const t=this.requestObj[e],s=this.requestConfigObj[e];t.cancel(s)}))}abortRequestByConfig(e){const t=this.generateKeyByConfig(e);this.requestObj[t]&&(this.requestObj[t].cancel(e),delete this.requestObj[t],delete this.requestConfigObj[t])}add(e,t,s){return new Promise(((i,n)=>{try{if("pause"===this.status||"prevent"===s?.preventDuplicateRequestsType){if(this.tasks.some((e=>e.requestKey===t))||this.runingReqKeys.includes(t))return}if("cancel"===s?.preventDuplicateRequestsType){if(this.tasks.some((e=>e.requestKey===t))&&(this.tasks=this.tasks.filter((e=>e.requestKey!==t))),this.runingReqKeys.includes(t))return this.maxReqNum++,this.runingReqKeys.push(t),this.tasks.unshift({isCancel:!0,task:e,requestKey:t,config:s,resolve:i,reject:n}),void this._run()}this.runingReqKeys.push(t),this.tasks.push({task:e,requestKey:t,config:s,resolve:i,reject:n}),this._run()}catch(e){n(e)}}))}_pause(){this.status="pause"}_start(){this.status="start",this._run()}_run(){if("pause"!==this.status)for(;this.runningCount<this.maxReqNum&&this.tasks.length>0;){const{isCancel:e,task:t,requestKey:s,config:i,resolve:n,reject:r}=this.tasks.shift();e&&this.maxReqNum--,this.runningCount++,t().then((e=>{this.runningCount--,"[object Object]"===Object.prototype.toString.call(e)&&i?.showIsComplete?n({...e,[i.showIsComplete]:0===this.runningCount}):n(e)})).catch((e=>{if(this.runningCount--,!this.axios.isCancel(e)&&i?.removeRemainingTasksWhenError){const e=this.tasks.map((e=>e.requestKey));this.tasks=[],this.runingReqKeys=this.runingReqKeys.filter((t=>!e.includes(t)))}r(e)})).finally((()=>{this.runingReqKeys.splice(this.runingReqKeys.indexOf(s),1),this._run()}))}}getCache(e,t){const{url:s,data:i={},config:n,method:r}=t;return new Promise(((t,h)=>{if(!this.cache.has(e)){delete n.cache;return void(["get","delete"].includes(r)?this[r](s,n):this[r](s,i,n)).then((s=>{this.setCache(e,s),t(s)})).catch((e=>{h(e)}))}const a=this.cache.get(e);this.cache.delete(e),this.cache.set(e,a),n.noShowLoading?t(a):(this.showLoadingFun(),setTimeout((()=>{this.hideLoadingFun(),t(a)}),this.timeout))}))}setCache(e,t){if(this.cache.has(e)&&this.cache.delete(e),this.cache.set(e,t),this.cache.size>this.cacheNum){const e=this.cache.keys().next().value;this.cache.delete(e)}}removeCache(){this.cache&&this.cache.clear()}get(e,t){if(t.cache){const s={url:e,config:t,method:"get"},i=t.params,n=this.generateKey(s,i);return this.getCache(n,s)}const s=t.params;if(delete t.params,t.isRefreshToken)return this.instance.request({url:e,params:s,...t,method:"GET"});const i=t.fullPath?this.generateKey({url:e,method:"get"},s):"GET#"+e;return this.add((()=>this.instance.request({url:e,params:s,...t,method:"GET"})),i,t)}post(e,t={},s={}){if(s.cache){const i={url:e,data:t,config:s,method:"post"},n=this.generateKey(i,t);return this.getCache(n,i)}if(s.isRefreshToken)return this.instance.request({url:e,data:t,...s,method:"POST"});const i=s.fullPath?this.generateKey({url:e,method:"post"},t):"POST#"+e;return this.add((()=>this.instance.request({url:e,data:t,...s,method:"POST"})),i,s)}delete(e,t={}){if(t.cache){const s={url:e,config:t,method:"delete"},i=t.params||t.data||{},n=this.generateKey(s,i);return this.getCache(n,s)}if(t.params){const s=t?.params||{};if(delete t.params,t.isRefreshToken)return this.instance.request({url:e,params:s,...t,method:"DELETE"});const i=t.fullPath?this.generateKey({url:e,method:"delete"},s):"DELETE#"+e;return this.add((()=>this.instance.request({url:e,params:s,...t,method:"DELETE"},i,t)))}const s=t?.data||{};if(delete t.data,t.isRefreshToken)return this.instance.request({url:e,data:s,...t,method:"DELETE"});const i=t.fullPath?this.generateKey({url:e,method:"delete"},s):"DELETE#"+e;return this.add((()=>this.instance.request({url:e,data:s,...t,method:"DELETE"},i,t)))}patch(e,t={},s={}){if(s.cache){const i={url:e,data:t,config:s,method:"patch"},n=this.generateKey(i,t);return this.getCache(n,i)}if(s.isRefreshToken)return this.instance.request({url:e,data:t,...s,method:"PATCH"});const i=s.fullPath?this.generateKey({url:e,method:"patch"},t):"PATCH#"+e;return this.add((()=>this.instance.request({url:e,data:t,...s,method:"PATCH"},i,s)))}put(e,t={},s={}){if(s.cache){const i={url:e,data:t,config:s,method:"put"},n=this.generateKey(i,t);return this.getCache(n,i)}if(s.isRefreshToken)return this.instance.request({url:e,data:t,...s,method:"PUT"});const i=s.fullPath?this.generateKey({url:e,method:"put"},t):"PUT#"+e;return this.add((()=>this.instance.request({url:e,data:t,...s,method:"PUT"},i,s)))}generateKey(e,t){const{method:s,url:i}=e;let n=s+"#"+i;const r=[];for(const[e,s]of Object.entries(t))r.push(`${e}=${s}`);return r.length>0&&(n+="?"+r.join("&")),n}generateKeyByConfig(e){if(e.isRefreshToken||!e.fullPath)return e.url;const{url:t,method:s,data:i,params:n}=e;let r={};try{i&&Object.assign(r,JSON.parse(i))}catch{r={}}n&&Object.assign(r,n);const h={url:t,method:s};return this.generateKey(h,r)}constructor(e,t,s){this.axios=e;const i=s.code||"code",n=s.authorizationKey||"Authorization",r=s.responseTypesStr||"arraybuffer,blob",h=s.setAuthorizationFun||function(e,t){return e.headers[n]=t,e};s.showLoadingFun&&(this.showLoadingFun=s.showLoadingFun),s.hideLoadingFun&&(this.hideLoadingFun=s.hideLoadingFun),this.timeout=s?.timeout||this.timeout,this.maxReqNum=s?.maxReqNum||this.maxReqNum,this.cacheNum=s?.cacheNum||this.cacheNum,this.cache=new Map,this.instance=t,this.instance.interceptors.request.use((t=>{const s=this.generateKeyByConfig(t);t?.noShowLoading||(this.requestingNum++,this.showLoadingFun(t,this.requestingNum));t.url&&t.preventDuplicateRequestsType&&"cancel"===t.preventDuplicateRequestsType&&this.requestObj[s]&&this.requestObj[s].cancel({config:t});const i=e.CancelToken;return this.requestObj[s]=i.source(),t.cancelToken=this.requestObj[s].token,this.requestConfigObj[s]=t,t}),(e=>Promise.reject(e))),this.instance.interceptors.response.use((async e=>{const{config:t,responseErr:a}=e,u=this.generateKeyByConfig(t);if(t?.noShowLoading||(this.requestingNum--,this.requestingNum<=0&&(this.requestObj={},this.requestConfigObj={},this.hideLoadingFun(t,this.requestingNum))),t&&(this.requestObj[u]&&delete this.requestObj[u],this.requestConfigObj[u]&&delete this.requestConfigObj[u]),a){if(s.openRefresh){const r=s.accessTokenExpirationCode||401;if(Number(e[i])===r){this._pause();const i=s.getRefreshTokenFun();if(!i){if(this.isShowReLoginDialog)return;return this.isShowReLoginDialog=!0,this.removeCache(),s.reloginFun(e),Promise.reject(e||"Error")}if(this.isRefresh)return new Promise((e=>{this.queue.push((()=>{e(this.instance.request(t))}))}));this.isRefresh=!0;try{const e=t.headers[n],r=s.getAuthorizationFun();return e!==r?(this._start(),this.instance.request(h(t,r))):(await s.refreshTokenStore(i),this._start(),this.queue.forEach((e=>e())),this.instance.request(t))}catch{if(this.isShowReLoginDialog)return;return this.isShowReLoginDialog=!0,this.removeCache(),s.reloginFun(e),Promise.reject(e||"Error")}finally{this.queue=[],this.isRefresh=!1}}const a=s.refreshTokenExpirationCode||403;if(Number(e[i])===a){if(this.isShowReLoginDialog)return;return this.isShowReLoginDialog=!0,this.removeCache(),s.reloginFun(e),Promise.reject(e||"Error")}}return Promise.reject(e||"Error")}if(r.toLocaleLowerCase().split(",").includes(t?.responseType?.toLocaleLowerCase()))return e.data;const o=JSON.parse(JSON.stringify(e));return t.cache||delete o.responseErr,delete o.config,s.responseResultFun?s.responseResultFun(o,t):o}),(t=>{const i=t?.message?.config||{},n=this.generateKeyByConfig(i);return i?.noShowLoading||(this.requestingNum--,this.requestingNum<=0&&(this.requestObj={},this.requestConfigObj={},s.hideLoadingFun&&s.hideLoadingFun(i,this.requestingNum))),e.isCancel(t)||delete this.requestObj[n],delete this.requestConfigObj[n],Promise.reject(t)}))}}export default e;
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-axios-optimize",
|
|
3
|
-
"version": "3.1.
|
|
4
|
-
"description": "vue项目对axios
|
|
3
|
+
"version": "3.1.3",
|
|
4
|
+
"description": "vue项目对axios请求的优化,实现精准控制全局加载动画,轻松实现重复请求时取消前面的请求或者阻止后面的请求,实现接口数据缓存,自主可中断请求,超时重发请求,最大高并发请求数量控制等",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
|
|
8
|
-
},
|
|
6
|
+
"scripts": {},
|
|
7
|
+
"types": "types/index.d.ts",
|
|
9
8
|
"keywords": [
|
|
10
9
|
"vue",
|
|
11
10
|
"axios",
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { AxiosInstance, AxiosRequestConfig } from "axios"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ========================================
|
|
5
|
+
* 配置选项类型
|
|
6
|
+
* ========================================
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** axiosOptimize 构造函数的 options 配置 */
|
|
10
|
+
export interface AxiosOptimizeOptions {
|
|
11
|
+
/** 响应数据中状态码的字段名,默认 "code" */
|
|
12
|
+
code?: string
|
|
13
|
+
/** 请求头中 authorization 的字段名,默认 "Authorization" */
|
|
14
|
+
authorizationKey?: string
|
|
15
|
+
/** 直接返回原始 data 的响应类型,逗号分隔,默认 "arraybuffer,blob" */
|
|
16
|
+
responseTypesStr?: string
|
|
17
|
+
/** 设置 authorization 的方法 */
|
|
18
|
+
setAuthorizationFun?: (config: AxiosRequestConfig, token: string) => AxiosRequestConfig
|
|
19
|
+
/** 获取当前 authorization 值的方法 */
|
|
20
|
+
getAuthorizationFun?: () => string
|
|
21
|
+
/** 显示全局加载动画的方法 */
|
|
22
|
+
showLoadingFun?: (config?: AxiosRequestConfig, requestingNum?: number) => void
|
|
23
|
+
/** 隐藏全局加载动画的方法 */
|
|
24
|
+
hideLoadingFun?: (config?: AxiosRequestConfig, requestingNum?: number) => void
|
|
25
|
+
/** 最大并发请求数量,默认 6 */
|
|
26
|
+
maxReqNum?: number
|
|
27
|
+
/** 最大缓存数量,默认 10 */
|
|
28
|
+
cacheNum?: number
|
|
29
|
+
/** 缓存数据时的伪加载时间(毫秒),默认 300 */
|
|
30
|
+
timeout?: number
|
|
31
|
+
/** 是否开启无感知刷新 token */
|
|
32
|
+
openRefresh?: boolean
|
|
33
|
+
/** accessToken 过期时的状态码,默认 401 */
|
|
34
|
+
accessTokenExpirationCode?: number
|
|
35
|
+
/** refreshToken 过期时的状态码,默认 403 */
|
|
36
|
+
refreshTokenExpirationCode?: number
|
|
37
|
+
/** 获取 refreshToken 的方法 */
|
|
38
|
+
getRefreshTokenFun?: () => string | undefined
|
|
39
|
+
/** 刷新 token 的方法,接收 refreshToken,resolve 新的 accessToken */
|
|
40
|
+
refreshTokenStore?: (refreshToken: string) => Promise<string>
|
|
41
|
+
/** 重新登录的方法 */
|
|
42
|
+
reloginFun?: (error: any) => void
|
|
43
|
+
/** 自定义响应结果处理方法 */
|
|
44
|
+
responseResultFun?: (response: any, config?: AxiosRequestConfig) => any
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 请求配置扩展(在 AxiosRequestConfig 基础上新增的字段) */
|
|
48
|
+
export interface AxiosOptimizeRequestConfig extends AxiosRequestConfig {
|
|
49
|
+
/** 是否使用缓存 */
|
|
50
|
+
cache?: boolean
|
|
51
|
+
/** 是否为刷新 token 的请求 */
|
|
52
|
+
isRefreshToken?: boolean
|
|
53
|
+
/** 是否使用完整路径(含参数)作为请求 key */
|
|
54
|
+
fullPath?: boolean
|
|
55
|
+
/** 是否不显示 loading */
|
|
56
|
+
noShowLoading?: boolean
|
|
57
|
+
/** 重复请求处理类型:取消前面 / 阻止后面 */
|
|
58
|
+
preventDuplicateRequestsType?: "cancel" | "prevent"
|
|
59
|
+
/** 某个请求报错时,阻止剩余未发起的请求 */
|
|
60
|
+
removeRemainingTasksWhenError?: boolean
|
|
61
|
+
/** 配置值作为返回字段名,表示此接口已全部请求完毕 */
|
|
62
|
+
showIsComplete?: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* ========================================
|
|
67
|
+
* axiosOptimize 主类
|
|
68
|
+
* ========================================
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
export default class AxiosOptimize {
|
|
72
|
+
constructor(axios: any, instance: AxiosInstance, options: AxiosOptimizeOptions)
|
|
73
|
+
|
|
74
|
+
/** 原始 axios */
|
|
75
|
+
axios: any
|
|
76
|
+
/** axios 实例 */
|
|
77
|
+
instance: AxiosInstance
|
|
78
|
+
|
|
79
|
+
/** 中断所有进行中的请求 */
|
|
80
|
+
abortAllRequests(): void
|
|
81
|
+
|
|
82
|
+
/** 根据配置中断指定请求 */
|
|
83
|
+
abortRequestByConfig(config: AxiosRequestConfig): void
|
|
84
|
+
|
|
85
|
+
/** GET 请求 */
|
|
86
|
+
get<T = any>(url: string, config?: AxiosOptimizeRequestConfig): Promise<T>
|
|
87
|
+
|
|
88
|
+
/** POST 请求 */
|
|
89
|
+
post<T = any>(url: string, data?: any, config?: AxiosOptimizeRequestConfig): Promise<T>
|
|
90
|
+
|
|
91
|
+
/** DELETE 请求 */
|
|
92
|
+
delete<T = any>(url: string, config?: AxiosOptimizeRequestConfig): Promise<T>
|
|
93
|
+
|
|
94
|
+
/** PATCH 请求 */
|
|
95
|
+
patch<T = any>(url: string, data?: any, config?: AxiosOptimizeRequestConfig): Promise<T>
|
|
96
|
+
|
|
97
|
+
/** PUT 请求 */
|
|
98
|
+
put<T = any>(url: string, data?: any, config?: AxiosOptimizeRequestConfig): Promise<T>
|
|
99
|
+
|
|
100
|
+
/** 清除所有接口缓存 */
|
|
101
|
+
removeCache(): void
|
|
102
|
+
|
|
103
|
+
/** 暂停请求队列 */
|
|
104
|
+
_pause(): void
|
|
105
|
+
|
|
106
|
+
/** 恢复请求队列 */
|
|
107
|
+
_start(): void
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* ========================================
|
|
112
|
+
* utils.js 工具函数类型
|
|
113
|
+
* ========================================
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
/** createCancelableRequest 返回值 */
|
|
117
|
+
export interface CancelableRequestResult {
|
|
118
|
+
/** 执行请求 */
|
|
119
|
+
request: () => Promise<any>
|
|
120
|
+
/** 取消请求 */
|
|
121
|
+
cancel: () => void
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** requestWithRetry 的重试配置 (get/delete) */
|
|
125
|
+
export interface RetryConfigForGetDelete {
|
|
126
|
+
/** 超时时间(毫秒),默认 60000 */
|
|
127
|
+
timeout?: number
|
|
128
|
+
/** 最大重试次数,默认 3 */
|
|
129
|
+
maxRetryTimes?: number
|
|
130
|
+
/** 重试提示消息 */
|
|
131
|
+
retryMessage?: string
|
|
132
|
+
/** 是否可手动取消 */
|
|
133
|
+
widthCancel?: boolean
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** requestWithRetry 的重试配置 (post/put/patch) */
|
|
137
|
+
export interface RetryConfigForPostPutPatch {
|
|
138
|
+
/** 超时时间(毫秒),默认 60000 */
|
|
139
|
+
timeout?: number
|
|
140
|
+
/** 最大重试次数,默认 3 */
|
|
141
|
+
maxRetryTimes?: number
|
|
142
|
+
/** 重试提示消息 */
|
|
143
|
+
retryMessage?: string
|
|
144
|
+
/** 是否可手动取消 */
|
|
145
|
+
widthCancel?: boolean
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** requestWithRetry 返回值(widthCancel 为 true 时) */
|
|
149
|
+
export interface RetryRequestResult {
|
|
150
|
+
/** 执行请求(每次调用会重置重试计数) */
|
|
151
|
+
request: () => Promise<any>
|
|
152
|
+
/** 手动取消请求 */
|
|
153
|
+
cancel: () => void
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 创建可取消请求
|
|
158
|
+
* @param axiosOptimizeInstance - axiosOptimize 实例
|
|
159
|
+
* @param method - 请求方法 (get/post/delete/patch/put)
|
|
160
|
+
* @param url - 请求地址
|
|
161
|
+
* @param config - get/delete 时的请求配置
|
|
162
|
+
* @param dataConfig - post/patch/put 时的额外配置
|
|
163
|
+
*/
|
|
164
|
+
export declare function createCancelableRequest(
|
|
165
|
+
axiosOptimizeInstance: AxiosOptimize,
|
|
166
|
+
method: string,
|
|
167
|
+
url: string,
|
|
168
|
+
config?: AxiosRequestConfig,
|
|
169
|
+
dataConfig?: AxiosRequestConfig
|
|
170
|
+
): CancelableRequestResult
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 创建超时重试请求
|
|
174
|
+
* @param axiosOptimizeInstance - axiosOptimize 实例
|
|
175
|
+
* @param method - 请求方法 (get/post/delete/patch/put)
|
|
176
|
+
* @param url - 请求地址
|
|
177
|
+
* @param config - get/delete 时的请求配置(含重试配置)
|
|
178
|
+
* @param dataConfig - post/put/patch 时的额外配置(含重试配置)
|
|
179
|
+
* @returns 当 widthCancel 为 true 时返回 { request, cancel },否则直接返回 Promise
|
|
180
|
+
*/
|
|
181
|
+
export declare function requestWithRetry(
|
|
182
|
+
axiosOptimizeInstance: AxiosOptimize,
|
|
183
|
+
method: string,
|
|
184
|
+
url: string,
|
|
185
|
+
config?: RetryConfigForGetDelete & AxiosRequestConfig,
|
|
186
|
+
dataConfig?: RetryConfigForPostPutPatch & AxiosRequestConfig
|
|
187
|
+
): Promise<any> | RetryRequestResult
|
package/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"axios";export function createCancelableRequest(t,a,n,c={},r={}){if(a=a.toLowerCase(),!t||"function"!=typeof t[a])throw new Error(`createCancelableRequest:axiosInstance 不存在 ${a} 方法`);const s=e.CancelToken.source(),o={...r,cancelToken:s.token};return{request:()=>{let e;return["get","delete"].includes(a)?e=t[a](n,c):["post","patch","put"].includes(a)&&(e=t[a](n,c,o)),e},cancel:()=>{if(["get","delete"].includes(a)){const e={url:n,method:a,data:c.data||{},params:c.params||{}};t.abortRequestByConfig(e)}else if(["post","patch","put"].includes(a)){const e={url:n,method:a,data:c,config:e};t.abortRequestByConfig(e)}}}}export function requestWithRetry(t,a,n,c={},r={}){if(a=a.toLowerCase(),!t||"function"!=typeof t[a])throw new Error(`createCancelableRequest:axiosInstance 不存在 ${a} 方法`);let s,o,l=0,i=null,u=!1,m=!1;["get","delete"].includes(a)?m=c?.widthCancel||m:["post","put","patch"].includes(a)&&(m=r?.widthCancel||!1),i=()=>{u=!0,o()};const d=()=>new Promise(((i,p)=>{let C=
|
|
1
|
+
import e from"axios";export function createCancelableRequest(t,a,n,c={},r={}){if(a=a.toLowerCase(),!t||"function"!=typeof t[a])throw new Error(`createCancelableRequest:axiosInstance 不存在 ${a} 方法`);const s=e.CancelToken.source(),o={...r,cancelToken:s.token};return{request:()=>{let e;return["get","delete"].includes(a)?e=t[a](n,c):["post","patch","put"].includes(a)&&(e=t[a](n,c,o)),e},cancel:()=>{if(["get","delete"].includes(a)){const e={url:n,method:a,data:c.data||{},params:c.params||{}};t.abortRequestByConfig(e)}else if(["post","patch","put"].includes(a)){const e={url:n,method:a,data:c,config:e};t.abortRequestByConfig(e)}}}}export function requestWithRetry(t,a,n,c={},r={}){if(a=a.toLowerCase(),!t||"function"!=typeof t[a])throw new Error(`createCancelableRequest:axiosInstance 不存在 ${a} 方法`);let s,o,l=0,i=null,u=!1,m=!1;["get","delete"].includes(a)?m=c?.widthCancel||m:["post","put","patch"].includes(a)&&(m=r?.widthCancel||!1),i=()=>{u=!0,o()};const d=()=>new Promise(((i,p)=>{let C=6e4,h=3,f="请求超时,重试中",R={};if(["get","delete"].includes(a)){C=c?.timeout||C,h=c?.maxRetryTimes||h,f=c?.retryMessage||f,R={...c,timeout:C,maxRetryTimes:h,currentRetryTimes:l,isManualCancel:u,widthCancel:m};const{request:e,cancel:r}=createCancelableRequest(t,a,n,R);s=e,o=r}else if(["post","put","patch"].includes(a)){C=r?.timeout||C,h=r?.maxRetryTimes||h,f=r?.retryMessage||f,R={...r,timeout:C,maxRetryTimes:h,currentRetryTimes:l,isManualCancel:u,widthCancel:m};const{request:e,cancel:i}=createCancelableRequest(t,a,n,c,R);s=e,o=i}const y=setTimeout((()=>{o(`请求超时(${C}ms),准备重试`),l++,l<=h&&!u?(console.log(`${f},当前重试次数:${l}/${h}`),d().then((e=>i(e))).catch((e=>p(e)))):p({name:"RetryExhaustedError",message:`请求超时,已重试${l-1}次,${u?"手动":"自动"}停止重试`,retryTimes:l,config:R})}),C);s().then((e=>{clearTimeout(y),i(e)})).catch((t=>{clearTimeout(y),"CanceledError"===t?.name&&u?p(t):"ECONNABORTED"===t?.code||e.isCancel(t)||p(t)}))})),p=()=>(l=0,u=!1,d());return m?{request:p,cancel:i}:p()}
|