@vef-framework/core 2.0.9 → 2.0.10
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/dist/cjs/http/client.cjs +1 -1
- package/dist/es/http/client.js +28 -25
- package/package.json +2 -2
package/dist/cjs/http/client.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("@vef-framework/shared"),g=require("axios")
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("@vef-framework/shared"),g=require("axios"),$=require("./errors.cjs"),m=/:(?<key>\w+)/g,R=/filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/,f="X-Skip-Authentication",k="1";class b{#e;#s;#t=!1;#n=[];constructor(e){this.#s=e;const{baseUrl:s,timeout:n=1e3*30}=e;this.#e=g.create({baseURL:s,allowAbsoluteUrls:!0,timeout:n,headers:{"Content-Type":"application/json"},paramsSerializer:t=>u.encodeQueryString(t,{arrayFormat:"repeat",skipNulls:!0,charset:"utf-8"}),responseType:"json",responseEncoding:"utf-8",validateStatus(t){return t>=200&&t<300},withCredentials:!1,timeoutErrorMessage:"请求超时"}),this.initInterceptors()}initInterceptors(){this.#e.interceptors.request.use(this.handleRequest.bind(this),this.handleRequestError.bind(this)),this.#e.interceptors.response.use(this.handleResponse.bind(this),this.handleResponseError.bind(this))}isBelongsTo(e,s){return u.isArray(s)?s.includes(e):e===s}async handleRequest(e){const s=e.headers[f]===k;if(this.#t&&!s&&!await new Promise(t=>{this.#n.push(t)}))throw new Error("登录已过期, 请重新登录");return s?delete e.headers[f]:await this.setAccessToken(e),this.replacePathParams(e),e}handleRequestError(e){const{showErrorMessage:s}=this.#s,n=e instanceof Error?e.message:String(e);return s?s(`发起请求失败: ${n||"未知错误"}`):console.error(`[HttpClient] ❌ 发起请求失败: ${n||"未知错误"}`),Promise.reject(e)}handleResponse(e){const{showWarningMessage:s,okCode:n=0}=this.#s,{code:t,message:o,data:r}=e.data;if(this.isBelongsTo(t,n))return e;throw s?s(o):console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`),new $.BusinessError(t,o,r)}async handleResponseError(e){const{showInfoMessage:s,showWarningMessage:n,showErrorMessage:t,tokenExpiredCode:o=[]}=this.#s;if(e instanceof g.CanceledError){if(e.response){const{method:a,url:c}=e.response.config;console.warn(`[HttpClient] ⚠️ [${a}: ${c}] 被取消`)}return}const{response:r}=e;if(r){const{status:a,config:c,data:l}=r,{code:d,message:i}=l,p=`[${c.method}: ${c.url}]`;switch(a){case 401:{if(this.isBelongsTo(d,o)){let h;if(this.#t?h=await new Promise(y=>{this.#n.push(y)}):h=await this.tryRefreshToken(),h)return this.retryRequest(c);const w="登录已过期, 请重新登录";s?s(w):console.info(`[HttpClient] ℹ️ ${w}`)}await this.#s.onUnauthenticated?.();break}case 403:{n?.(`${i}, 请联系管理员为您开通`),console.warn(`[HttpClient] ⚠️ ${p} 访问被拒绝: ${i}`),await this.#s.onAccessDenied?.();break}case 400:{n?n(i):console.warn(`[HttpClient] ⚠️ ${p} 参数错误: ${i}`);break}default:t?t(i):console.error(`[HttpClient] ❌ ${p} 返回错误: ${i}`)}}else{const a=`请求失败: ${e.message||"未知错误"}`;t?t(a):console.error(`[HttpClient] ❌ ${a}`)}throw e}async setAccessToken(e){const{getAuthTokens:s}=this.#s;if(s){const t=(await s())?.accessToken;t&&(e.headers.Authorization=`Bearer ${t}`)}}replacePathParams(e){const{url:s,params:n={}}=e;return s&&m.test(s)&&(e.url=s.replaceAll(m,(t,o)=>{if(!Object.hasOwn(n,o))return console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 未在查询参数中定义, 请检查`),"unknown";const r=n[o];return u.isNullish(r)?(console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`),"unknown"):r})),e}async tryRefreshToken(){const{getAuthTokens:e,refreshToken:s,setAuthTokens:n}=this.#s;if(!e||!s||!n)return!1;this.#t=!0;let t=!1;try{const o=await e();if(!o)return!1;const r=await s(o);return await n(Object.freeze(r)),t=!0}catch(o){return console.error(`[HttpClient] ❌ 刷新令牌失败: ${o}`),!1}finally{this.#t=!1;for(const o of this.#n)o(t);this.#n=[]}}async retryRequest(e){const s={...e};return await this.setAccessToken(s),this.#e(s)}async get(e,s){return(await this.#e.get(e,s)).data}async post(e,s){const{data:n,...t}=s??{};return(await this.#e.post(e,n,t)).data}async put(e,s){const{data:n,...t}=s??{};return(await this.#e.put(e,n,t)).data}async delete(e,s){return(await this.#e.delete(e,s)).data}async upload(e,s){const{data:n,onProgress:t,...o}=s??{};return(await this.#e.postForm(e,n,{...o,onUploadProgress:u.isFunction(t)?t:void 0})).data}async download(e,s){const{onProgress:n,filename:t,...o}=s??{},{data:r,headers:a}=await this.#e.get(e,{...o,responseType:"blob",responseEncoding:"binary",onDownloadProgress:u.isFunction(n)?n:void 0});try{const l=JSON.parse(await r.text());throw new Error(l.message)}catch{}const c=a["content-disposition"];if(u.isString(c)){const l=R.exec(c);if(l&&l.groups){const{name:d}=l.groups,i=decodeURIComponent(d),p=URL.createObjectURL(r);try{const h=document.createElement("a");h.href=p,h.download=u.isFunction(t)?t(i):t??i,h.click()}finally{URL.revokeObjectURL(p)}}}}}exports.HttpClient=b;exports.skipAuthenticationHeader=f;exports.skipAuthenticationValue=k;
|
package/dist/es/http/client.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { encodeQueryString as
|
|
2
|
-
import
|
|
3
|
-
import { BusinessError as
|
|
4
|
-
const w = /:(?<key>\w+)/g,
|
|
5
|
-
class
|
|
1
|
+
import { encodeQueryString as k, isArray as y, isNullish as $, isFunction as d, isString as R } from "@vef-framework/shared";
|
|
2
|
+
import C, { CanceledError as T } from "axios";
|
|
3
|
+
import { BusinessError as b } from "./errors.js";
|
|
4
|
+
const w = /:(?<key>\w+)/g, E = /filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/, g = "X-Skip-Authentication", A = "1";
|
|
5
|
+
class q {
|
|
6
6
|
/**
|
|
7
7
|
* The axios instance.
|
|
8
8
|
*/
|
|
@@ -25,14 +25,14 @@ class O {
|
|
|
25
25
|
baseUrl: s,
|
|
26
26
|
timeout: n = 1e3 * 30
|
|
27
27
|
} = e;
|
|
28
|
-
this.#e =
|
|
28
|
+
this.#e = C.create({
|
|
29
29
|
baseURL: s,
|
|
30
30
|
allowAbsoluteUrls: !0,
|
|
31
31
|
timeout: n,
|
|
32
32
|
headers: {
|
|
33
33
|
"Content-Type": "application/json"
|
|
34
34
|
},
|
|
35
|
-
paramsSerializer: (t) =>
|
|
35
|
+
paramsSerializer: (t) => k(
|
|
36
36
|
t,
|
|
37
37
|
{
|
|
38
38
|
arrayFormat: "repeat",
|
|
@@ -66,7 +66,7 @@ class O {
|
|
|
66
66
|
* @returns The result.
|
|
67
67
|
*/
|
|
68
68
|
isBelongsTo(e, s) {
|
|
69
|
-
return
|
|
69
|
+
return y(s) ? s.includes(e) : e === s;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
72
|
* Handle the request.
|
|
@@ -75,7 +75,7 @@ class O {
|
|
|
75
75
|
* @returns The axios request config.
|
|
76
76
|
*/
|
|
77
77
|
async handleRequest(e) {
|
|
78
|
-
const s = e.headers[g] ===
|
|
78
|
+
const s = e.headers[g] === A;
|
|
79
79
|
if (this.#t && !s && !await new Promise((t) => {
|
|
80
80
|
this.#n.push(t);
|
|
81
81
|
}))
|
|
@@ -108,7 +108,7 @@ class O {
|
|
|
108
108
|
} = e.data;
|
|
109
109
|
if (this.isBelongsTo(t, n))
|
|
110
110
|
return e;
|
|
111
|
-
throw s ? s(o) : console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`), new
|
|
111
|
+
throw s ? s(o) : console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`), new b(t, o, r);
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
114
|
* Handle the response error.
|
|
@@ -122,7 +122,7 @@ class O {
|
|
|
122
122
|
showErrorMessage: t,
|
|
123
123
|
tokenExpiredCode: o = []
|
|
124
124
|
} = this.#s;
|
|
125
|
-
if (e instanceof
|
|
125
|
+
if (e instanceof T) {
|
|
126
126
|
if (e.response) {
|
|
127
127
|
const { method: i, url: c } = e.response.config;
|
|
128
128
|
console.warn(`[HttpClient] ⚠️ [${i}: ${c}] 被取消`);
|
|
@@ -135,11 +135,14 @@ class O {
|
|
|
135
135
|
status: i,
|
|
136
136
|
config: c,
|
|
137
137
|
data: l
|
|
138
|
-
} = r, { code: p, message: a } = l,
|
|
138
|
+
} = r, { code: p, message: a } = l, u = `[${c.method}: ${c.url}]`;
|
|
139
139
|
switch (i) {
|
|
140
140
|
case 401: {
|
|
141
141
|
if (this.isBelongsTo(p, o)) {
|
|
142
|
-
|
|
142
|
+
let h;
|
|
143
|
+
if (this.#t ? h = await new Promise((m) => {
|
|
144
|
+
this.#n.push(m);
|
|
145
|
+
}) : h = await this.tryRefreshToken(), h)
|
|
143
146
|
return this.retryRequest(c);
|
|
144
147
|
const f = "登录已过期, 请重新登录";
|
|
145
148
|
s ? s(f) : console.info(`[HttpClient] ℹ️ ${f}`);
|
|
@@ -148,15 +151,15 @@ class O {
|
|
|
148
151
|
break;
|
|
149
152
|
}
|
|
150
153
|
case 403: {
|
|
151
|
-
n?.(`${a}, 请联系管理员为您开通`), console.warn(`[HttpClient] ⚠️ ${
|
|
154
|
+
n?.(`${a}, 请联系管理员为您开通`), console.warn(`[HttpClient] ⚠️ ${u} 访问被拒绝: ${a}`), await this.#s.onAccessDenied?.();
|
|
152
155
|
break;
|
|
153
156
|
}
|
|
154
157
|
case 400: {
|
|
155
|
-
n ? n(a) : console.warn(`[HttpClient] ⚠️ ${
|
|
158
|
+
n ? n(a) : console.warn(`[HttpClient] ⚠️ ${u} 参数错误: ${a}`);
|
|
156
159
|
break;
|
|
157
160
|
}
|
|
158
161
|
default:
|
|
159
|
-
t ? t(a) : console.error(`[HttpClient] ❌ ${
|
|
162
|
+
t ? t(a) : console.error(`[HttpClient] ❌ ${u} 返回错误: ${a}`);
|
|
160
163
|
}
|
|
161
164
|
} else {
|
|
162
165
|
const i = `请求失败: ${e.message || "未知错误"}`;
|
|
@@ -188,7 +191,7 @@ class O {
|
|
|
188
191
|
if (!Object.hasOwn(n, o))
|
|
189
192
|
return console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 未在查询参数中定义, 请检查`), "unknown";
|
|
190
193
|
const r = n[o];
|
|
191
|
-
return
|
|
194
|
+
return $(r) ? (console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`), "unknown") : r;
|
|
192
195
|
})), e;
|
|
193
196
|
}
|
|
194
197
|
/**
|
|
@@ -336,22 +339,22 @@ class O {
|
|
|
336
339
|
} catch {
|
|
337
340
|
}
|
|
338
341
|
const c = i["content-disposition"];
|
|
339
|
-
if (
|
|
340
|
-
const l =
|
|
342
|
+
if (R(c)) {
|
|
343
|
+
const l = E.exec(c);
|
|
341
344
|
if (l && l.groups) {
|
|
342
|
-
const { name: p } = l.groups, a = decodeURIComponent(p),
|
|
345
|
+
const { name: p } = l.groups, a = decodeURIComponent(p), u = URL.createObjectURL(r);
|
|
343
346
|
try {
|
|
344
|
-
const
|
|
345
|
-
|
|
347
|
+
const h = document.createElement("a");
|
|
348
|
+
h.href = u, h.download = d(t) ? t(a) : t ?? a, h.click();
|
|
346
349
|
} finally {
|
|
347
|
-
URL.revokeObjectURL(
|
|
350
|
+
URL.revokeObjectURL(u);
|
|
348
351
|
}
|
|
349
352
|
}
|
|
350
353
|
}
|
|
351
354
|
}
|
|
352
355
|
}
|
|
353
356
|
export {
|
|
354
|
-
|
|
357
|
+
q as HttpClient,
|
|
355
358
|
g as skipAuthenticationHeader,
|
|
356
|
-
|
|
359
|
+
A as skipAuthenticationValue
|
|
357
360
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vef-framework/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.10",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Core features for VEF framework",
|
|
7
7
|
"author": {
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"use-immer": "^0.11.0",
|
|
65
65
|
"xstate": "^5.24.0",
|
|
66
66
|
"zustand": "^5.0.8",
|
|
67
|
-
"@vef-framework/shared": "2.0.
|
|
67
|
+
"@vef-framework/shared": "2.0.10"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"react": "^19.2.0"
|