@vef-framework/core 2.0.8 → 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 +29 -28
- 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,14 +135,15 @@ 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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
142
|
+
let h;
|
|
143
|
+
if (this.#t ? h = await new Promise((m) => {
|
|
144
|
+
this.#n.push(m);
|
|
145
|
+
}) : h = await this.tryRefreshToken(), h)
|
|
146
|
+
return this.retryRequest(c);
|
|
146
147
|
const f = "登录已过期, 请重新登录";
|
|
147
148
|
s ? s(f) : console.info(`[HttpClient] ℹ️ ${f}`);
|
|
148
149
|
}
|
|
@@ -150,15 +151,15 @@ class O {
|
|
|
150
151
|
break;
|
|
151
152
|
}
|
|
152
153
|
case 403: {
|
|
153
|
-
n?.(`${a}, 请联系管理员为您开通`), console.warn(`[HttpClient] ⚠️ ${
|
|
154
|
+
n?.(`${a}, 请联系管理员为您开通`), console.warn(`[HttpClient] ⚠️ ${u} 访问被拒绝: ${a}`), await this.#s.onAccessDenied?.();
|
|
154
155
|
break;
|
|
155
156
|
}
|
|
156
157
|
case 400: {
|
|
157
|
-
n ? n(a) : console.warn(`[HttpClient] ⚠️ ${
|
|
158
|
+
n ? n(a) : console.warn(`[HttpClient] ⚠️ ${u} 参数错误: ${a}`);
|
|
158
159
|
break;
|
|
159
160
|
}
|
|
160
161
|
default:
|
|
161
|
-
t ? t(a) : console.error(`[HttpClient] ❌ ${
|
|
162
|
+
t ? t(a) : console.error(`[HttpClient] ❌ ${u} 返回错误: ${a}`);
|
|
162
163
|
}
|
|
163
164
|
} else {
|
|
164
165
|
const i = `请求失败: ${e.message || "未知错误"}`;
|
|
@@ -190,7 +191,7 @@ class O {
|
|
|
190
191
|
if (!Object.hasOwn(n, o))
|
|
191
192
|
return console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 未在查询参数中定义, 请检查`), "unknown";
|
|
192
193
|
const r = n[o];
|
|
193
|
-
return
|
|
194
|
+
return $(r) ? (console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`), "unknown") : r;
|
|
194
195
|
})), e;
|
|
195
196
|
}
|
|
196
197
|
/**
|
|
@@ -338,22 +339,22 @@ class O {
|
|
|
338
339
|
} catch {
|
|
339
340
|
}
|
|
340
341
|
const c = i["content-disposition"];
|
|
341
|
-
if (
|
|
342
|
-
const l =
|
|
342
|
+
if (R(c)) {
|
|
343
|
+
const l = E.exec(c);
|
|
343
344
|
if (l && l.groups) {
|
|
344
|
-
const { name: p } = l.groups, a = decodeURIComponent(p),
|
|
345
|
+
const { name: p } = l.groups, a = decodeURIComponent(p), u = URL.createObjectURL(r);
|
|
345
346
|
try {
|
|
346
|
-
const
|
|
347
|
-
|
|
347
|
+
const h = document.createElement("a");
|
|
348
|
+
h.href = u, h.download = d(t) ? t(a) : t ?? a, h.click();
|
|
348
349
|
} finally {
|
|
349
|
-
URL.revokeObjectURL(
|
|
350
|
+
URL.revokeObjectURL(u);
|
|
350
351
|
}
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
}
|
|
354
355
|
}
|
|
355
356
|
export {
|
|
356
|
-
|
|
357
|
+
q as HttpClient,
|
|
357
358
|
g as skipAuthenticationHeader,
|
|
358
|
-
|
|
359
|
+
A as skipAuthenticationValue
|
|
359
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"
|