@whitesev/utils 2.9.11 → 2.9.13
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 +176 -176
- package/dist/index.amd.js +159 -101
- package/dist/index.amd.js.map +1 -1
- package/dist/index.amd.min.js +1 -1
- package/dist/index.amd.min.js.map +1 -1
- package/dist/index.cjs.js +159 -101
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.cjs.min.js +1 -1
- package/dist/index.cjs.min.js.map +1 -1
- package/dist/index.esm.js +159 -101
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/index.iife.js +159 -101
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +1 -1
- package/dist/index.iife.min.js.map +1 -1
- package/dist/index.system.js +159 -101
- package/dist/index.system.js.map +1 -1
- package/dist/index.system.min.js +1 -1
- package/dist/index.system.min.js.map +1 -1
- package/dist/index.umd.js +159 -101
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/index.umd.min.js.map +1 -1
- package/dist/types/src/Dictionary.d.ts +2 -0
- package/dist/types/src/Utils.d.ts +5 -2
- package/dist/types/src/types/Httpx.d.ts +1344 -1344
- package/dist/types/src/types/Log.d.ts +19 -19
- package/dist/types/src/types/Progress.d.ts +20 -20
- package/dist/types/src/types/React.d.ts +119 -119
- package/dist/types/src/types/TryCatch.d.ts +9 -9
- package/dist/types/src/types/UtilsGMCookie.d.ts +93 -93
- package/dist/types/src/types/UtilsGMMenu.d.ts +77 -77
- package/dist/types/src/types/Vue2.d.ts +166 -166
- package/dist/types/src/types/WindowApi.d.ts +14 -14
- package/dist/types/src/types/ajaxHooker.d.ts +155 -155
- package/dist/types/src/types/env.d.ts +7 -7
- package/dist/types/src/types/global.d.ts +31 -31
- package/package.json +26 -24
- package/src/ColorConversion.ts +118 -118
- package/src/CommonUtil.ts +301 -285
- package/src/DOMUtils.ts +251 -251
- package/src/Dictionary.ts +205 -199
- package/src/GBKEncoder.ts +108 -108
- package/src/Hooks.ts +73 -73
- package/src/Httpx.ts +1457 -1457
- package/src/LockFunction.ts +65 -62
- package/src/Log.ts +233 -233
- package/src/ModuleRaid.js +378 -360
- package/src/Progress.ts +108 -108
- package/src/TryCatch.ts +86 -86
- package/src/Utils.ts +3860 -3852
- package/src/UtilsCommon.ts +14 -14
- package/src/UtilsGMCookie.ts +273 -273
- package/src/UtilsGMMenu.ts +460 -460
- package/src/Vue.ts +233 -233
- package/src/WindowApi.ts +59 -59
- package/src/ajaxHooker/ajaxHooker.js +606 -538
- package/src/ajaxHooker/ajaxHooker1.2.4.js +440 -438
- package/src/indexedDB.ts +497 -497
- package/src/types/Httpx.d.ts +1344 -1344
- package/src/types/Log.d.ts +19 -19
- package/src/types/Progress.d.ts +20 -20
- package/src/types/React.d.ts +119 -119
- package/src/types/TryCatch.d.ts +9 -9
- package/src/types/UtilsGMCookie.d.ts +93 -93
- package/src/types/UtilsGMMenu.d.ts +77 -77
- package/src/types/Vue2.d.ts +166 -166
- package/src/types/WindowApi.d.ts +14 -14
- package/src/types/ajaxHooker.d.ts +155 -155
- package/src/types/env.d.ts +7 -7
- package/src/types/global.d.ts +31 -31
package/src/Httpx.ts
CHANGED
|
@@ -1,1457 +1,1457 @@
|
|
|
1
|
-
import { CommonUtil } from "./CommonUtil";
|
|
2
|
-
import { TryCatch } from "./TryCatch";
|
|
3
|
-
import type {
|
|
4
|
-
HttpxAllowInterceptConfig,
|
|
5
|
-
HttpxHookErrorData,
|
|
6
|
-
HttpxInitOption,
|
|
7
|
-
HttpxMethod,
|
|
8
|
-
HttpxPromise,
|
|
9
|
-
HttpxRequestOption,
|
|
10
|
-
HttpxResponse,
|
|
11
|
-
HttpxResponseData,
|
|
12
|
-
} from "./types/Httpx";
|
|
13
|
-
import { GenerateUUID } from "./UtilsCommon";
|
|
14
|
-
|
|
15
|
-
export class Httpx {
|
|
16
|
-
private GM_Api = {
|
|
17
|
-
xmlHttpRequest: null as ((...args: any[]) => any) | null,
|
|
18
|
-
};
|
|
19
|
-
private HttpxRequestHook = {
|
|
20
|
-
/**
|
|
21
|
-
* @private
|
|
22
|
-
*/
|
|
23
|
-
$config: {
|
|
24
|
-
configList: <
|
|
25
|
-
{
|
|
26
|
-
id: string;
|
|
27
|
-
fn: ((...args: any[]) => any) | Promise<(...args: any[]) => any>;
|
|
28
|
-
}[]
|
|
29
|
-
>[],
|
|
30
|
-
},
|
|
31
|
-
/**
|
|
32
|
-
* 发送请求前的回调
|
|
33
|
-
* 如果返回false则阻止本次返回
|
|
34
|
-
* @param details 当前的请求配置
|
|
35
|
-
* @private
|
|
36
|
-
*/
|
|
37
|
-
async beforeRequestCallBack(details: HttpxRequestOption) {
|
|
38
|
-
if (typeof details.allowInterceptConfig === "boolean") {
|
|
39
|
-
if (!details.allowInterceptConfig) {
|
|
40
|
-
// 不允许拦截
|
|
41
|
-
return details;
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
if (details.allowInterceptConfig != null) {
|
|
45
|
-
// 配置存在
|
|
46
|
-
// 细分处理是否拦截
|
|
47
|
-
if (
|
|
48
|
-
typeof details.allowInterceptConfig.beforeRequest === "boolean" &&
|
|
49
|
-
!details.allowInterceptConfig.beforeRequest
|
|
50
|
-
) {
|
|
51
|
-
// 设置了禁止拦截
|
|
52
|
-
return details;
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
// 配置不存在
|
|
56
|
-
// 默认允许拦截
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
for (let index = 0; index < this.$config.configList.length; index++) {
|
|
60
|
-
const item = this.$config.configList[index];
|
|
61
|
-
if (typeof item.fn === "function") {
|
|
62
|
-
const result = await item.fn(details);
|
|
63
|
-
if (result == null) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return details;
|
|
69
|
-
},
|
|
70
|
-
/**
|
|
71
|
-
* 添加请求前的回调处理配置
|
|
72
|
-
*/
|
|
73
|
-
add(fn: (...args: any[]) => any) {
|
|
74
|
-
if (typeof fn === "function") {
|
|
75
|
-
const uuid = GenerateUUID();
|
|
76
|
-
this.$config.configList.push({
|
|
77
|
-
id: uuid,
|
|
78
|
-
fn: fn,
|
|
79
|
-
});
|
|
80
|
-
return uuid;
|
|
81
|
-
} else {
|
|
82
|
-
console.warn("[Httpx-HttpxRequestHook.addBeforeRequestCallBack] fn is not a function");
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
/**
|
|
86
|
-
* 删除请求前的回调处理配置
|
|
87
|
-
* @param id
|
|
88
|
-
*/
|
|
89
|
-
delete(id: string) {
|
|
90
|
-
if (typeof id === "string") {
|
|
91
|
-
const findIndex = this.$config.configList.findIndex((item) => item.id === id);
|
|
92
|
-
if (findIndex !== -1) {
|
|
93
|
-
this.$config.configList.splice(findIndex, 1);
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return false;
|
|
98
|
-
},
|
|
99
|
-
/**
|
|
100
|
-
* 清空设置的请求前的回调处理配置
|
|
101
|
-
*/
|
|
102
|
-
clearAll() {
|
|
103
|
-
this.$config.configList = [];
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
private HttpxResponseHook = {
|
|
107
|
-
/**
|
|
108
|
-
* @private
|
|
109
|
-
*/
|
|
110
|
-
$config: {
|
|
111
|
-
configList: <
|
|
112
|
-
{
|
|
113
|
-
id: string;
|
|
114
|
-
successFn?: (...args: any[]) => any | Promise<(...args: any[]) => any>;
|
|
115
|
-
errorFn?: (...args: any[]) => any | Promise<(...args: any[]) => any>;
|
|
116
|
-
}[]
|
|
117
|
-
>[],
|
|
118
|
-
},
|
|
119
|
-
/**
|
|
120
|
-
* 成功的回调
|
|
121
|
-
* @param response 响应
|
|
122
|
-
* @param details 请求的配置
|
|
123
|
-
*/
|
|
124
|
-
async successResponseCallBack(response: HttpxResponseData<HttpxRequestOption>, details: HttpxRequestOption) {
|
|
125
|
-
if (typeof details.allowInterceptConfig === "boolean") {
|
|
126
|
-
if (!details.allowInterceptConfig) {
|
|
127
|
-
// 不允许拦截
|
|
128
|
-
return details;
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
if (details.allowInterceptConfig != null) {
|
|
132
|
-
// 配置存在
|
|
133
|
-
// 细分处理是否拦截
|
|
134
|
-
if (
|
|
135
|
-
typeof details.allowInterceptConfig.afterResponseSuccess === "boolean" &&
|
|
136
|
-
!details.allowInterceptConfig.afterResponseSuccess
|
|
137
|
-
) {
|
|
138
|
-
// 设置了禁止拦截
|
|
139
|
-
return details;
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
// 配置不存在
|
|
143
|
-
// 默认允许拦截
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
for (let index = 0; index < this.$config.configList.length; index++) {
|
|
147
|
-
const item = this.$config.configList[index];
|
|
148
|
-
if (typeof item.successFn === "function") {
|
|
149
|
-
const result = await item.successFn(response, details);
|
|
150
|
-
if (result == null) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return response;
|
|
156
|
-
},
|
|
157
|
-
/**
|
|
158
|
-
* 失败的回调
|
|
159
|
-
* @param data 配置
|
|
160
|
-
* @returns
|
|
161
|
-
* 返回null|undefined就是拦截掉了
|
|
162
|
-
*/
|
|
163
|
-
async errorResponseCallBack<T extends HttpxHookErrorData>(data: T) {
|
|
164
|
-
if (typeof data.details.allowInterceptConfig === "boolean") {
|
|
165
|
-
if (!data.details.allowInterceptConfig) {
|
|
166
|
-
// 不允许拦截
|
|
167
|
-
return data;
|
|
168
|
-
}
|
|
169
|
-
} else {
|
|
170
|
-
if (data.details.allowInterceptConfig != null) {
|
|
171
|
-
// 配置存在
|
|
172
|
-
// 细分处理是否拦截
|
|
173
|
-
if (
|
|
174
|
-
typeof data.details.allowInterceptConfig.afterResponseError === "boolean" &&
|
|
175
|
-
!data.details.allowInterceptConfig.afterResponseError
|
|
176
|
-
) {
|
|
177
|
-
// 设置了禁止拦截
|
|
178
|
-
return data;
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
// 配置不存在
|
|
182
|
-
// 默认允许拦截
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
for (let index = 0; index < this.$config.configList.length; index++) {
|
|
186
|
-
const item = this.$config.configList[index];
|
|
187
|
-
if (typeof item.errorFn === "function") {
|
|
188
|
-
const result = await item.errorFn(data);
|
|
189
|
-
if (result == null) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return data;
|
|
195
|
-
},
|
|
196
|
-
/**
|
|
197
|
-
* 添加请求前的回调处理配置
|
|
198
|
-
*/
|
|
199
|
-
add(successFn?: (...args: any[]) => any, errorFn?: (...args: any[]) => any) {
|
|
200
|
-
const id = GenerateUUID();
|
|
201
|
-
this.$config.configList.push({
|
|
202
|
-
id: id,
|
|
203
|
-
successFn: successFn,
|
|
204
|
-
errorFn: errorFn,
|
|
205
|
-
});
|
|
206
|
-
return id;
|
|
207
|
-
},
|
|
208
|
-
/**
|
|
209
|
-
* 删除请求前的回调处理配置
|
|
210
|
-
* @param id
|
|
211
|
-
*/
|
|
212
|
-
delete(id: string) {
|
|
213
|
-
if (typeof id === "string") {
|
|
214
|
-
const findIndex = this.$config.configList.findIndex((item) => item.id === id);
|
|
215
|
-
if (findIndex !== -1) {
|
|
216
|
-
this.$config.configList.splice(findIndex, 1);
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return false;
|
|
221
|
-
},
|
|
222
|
-
/**
|
|
223
|
-
* 清空设置的请求前的回调处理配置
|
|
224
|
-
*/
|
|
225
|
-
clearAll() {
|
|
226
|
-
this.$config.configList = [];
|
|
227
|
-
},
|
|
228
|
-
};
|
|
229
|
-
private HttpxRequestOption = {
|
|
230
|
-
context: this,
|
|
231
|
-
/**
|
|
232
|
-
* 对请求的参数进行合并处理
|
|
233
|
-
*/
|
|
234
|
-
handleBeforeRequestOptionArgs(...args: (HttpxRequestOption | string)[]) {
|
|
235
|
-
const option: HttpxRequestOption = {
|
|
236
|
-
url: void 0 as any as string,
|
|
237
|
-
};
|
|
238
|
-
if (typeof args[0] === "string") {
|
|
239
|
-
/* 传入的是url,转为配置 */
|
|
240
|
-
const url = args[0];
|
|
241
|
-
option.url = url;
|
|
242
|
-
if (typeof args[1] === "object") {
|
|
243
|
-
/* 处理第二个参数details */
|
|
244
|
-
const optionArg = args[1];
|
|
245
|
-
CommonUtil.assign(option, optionArg, true);
|
|
246
|
-
option.url = url;
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
/* 传入的是配置 */
|
|
250
|
-
const optionArg = args[0];
|
|
251
|
-
CommonUtil.assign(option, optionArg, true);
|
|
252
|
-
}
|
|
253
|
-
return option;
|
|
254
|
-
},
|
|
255
|
-
/**
|
|
256
|
-
* 获取请求配置
|
|
257
|
-
* @param method 当前请求方法,默认get
|
|
258
|
-
* @param userRequestOption 用户的请求配置
|
|
259
|
-
* @param resolve promise回调
|
|
260
|
-
* @param reject promise抛出错误回调
|
|
261
|
-
*/
|
|
262
|
-
getRequestOption(
|
|
263
|
-
method: HttpxMethod,
|
|
264
|
-
userRequestOption: HttpxRequestOption,
|
|
265
|
-
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
266
|
-
reject: (...args: any[]) => void
|
|
267
|
-
) {
|
|
268
|
-
const that = this;
|
|
269
|
-
let url = userRequestOption.url || this.context.#defaultRequestOption.url;
|
|
270
|
-
if (typeof url === "string") {
|
|
271
|
-
// 去除左右空格
|
|
272
|
-
url = url.trim();
|
|
273
|
-
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
274
|
-
// 标准的http请求
|
|
275
|
-
} else {
|
|
276
|
-
if (typeof this.context.#defaultInitOption.baseURL === "string") {
|
|
277
|
-
// 设置了基础域
|
|
278
|
-
url = this.context.#defaultInitOption.baseURL + url;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
const requestOption = <Required<HttpxRequestOption>>{
|
|
283
|
-
url: url,
|
|
284
|
-
method: (method || "GET").toString().toUpperCase().trim(),
|
|
285
|
-
timeout: userRequestOption.timeout || this.context.#defaultRequestOption.timeout,
|
|
286
|
-
responseType: userRequestOption.responseType || this.context.#defaultRequestOption.responseType,
|
|
287
|
-
/* 对象使用深拷贝 */
|
|
288
|
-
headers: CommonUtil.deepClone(this.context.#defaultRequestOption.headers),
|
|
289
|
-
data: userRequestOption.data || this.context.#defaultRequestOption.data,
|
|
290
|
-
redirect: userRequestOption.redirect || this.context.#defaultRequestOption.redirect,
|
|
291
|
-
cookie: userRequestOption.cookie || this.context.#defaultRequestOption.cookie,
|
|
292
|
-
cookiePartition: userRequestOption.cookiePartition || this.context.#defaultRequestOption.cookiePartition,
|
|
293
|
-
binary: userRequestOption.binary || this.context.#defaultRequestOption.binary,
|
|
294
|
-
nocache: userRequestOption.nocache || this.context.#defaultRequestOption.nocache,
|
|
295
|
-
revalidate: userRequestOption.revalidate || this.context.#defaultRequestOption.revalidate,
|
|
296
|
-
/* 对象使用深拷贝 */
|
|
297
|
-
context: CommonUtil.deepClone(userRequestOption.context || this.context.#defaultRequestOption.context),
|
|
298
|
-
overrideMimeType: userRequestOption.overrideMimeType || this.context.#defaultRequestOption.overrideMimeType,
|
|
299
|
-
anonymous: userRequestOption.anonymous || this.context.#defaultRequestOption.anonymous,
|
|
300
|
-
fetch: userRequestOption.fetch || this.context.#defaultRequestOption.fetch,
|
|
301
|
-
/* 对象使用深拷贝 */
|
|
302
|
-
fetchInit: CommonUtil.deepClone(this.context.#defaultRequestOption.fetchInit),
|
|
303
|
-
allowInterceptConfig: {
|
|
304
|
-
beforeRequest: (this.context.#defaultRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig)
|
|
305
|
-
.beforeRequest,
|
|
306
|
-
afterResponseSuccess: (this.context.#defaultRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig)
|
|
307
|
-
.afterResponseSuccess,
|
|
308
|
-
afterResponseError: (this.context.#defaultRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig)
|
|
309
|
-
.afterResponseError,
|
|
310
|
-
},
|
|
311
|
-
user: userRequestOption.user || this.context.#defaultRequestOption.user,
|
|
312
|
-
password: userRequestOption.password || this.context.#defaultRequestOption.password,
|
|
313
|
-
onabort(...args) {
|
|
314
|
-
that.context.HttpxResponseCallBack.onAbort(
|
|
315
|
-
userRequestOption as Required<HttpxRequestOption>,
|
|
316
|
-
resolve,
|
|
317
|
-
reject,
|
|
318
|
-
args
|
|
319
|
-
);
|
|
320
|
-
},
|
|
321
|
-
onerror(...args) {
|
|
322
|
-
that.context.HttpxResponseCallBack.onError(
|
|
323
|
-
userRequestOption as Required<HttpxRequestOption>,
|
|
324
|
-
resolve,
|
|
325
|
-
reject,
|
|
326
|
-
args
|
|
327
|
-
);
|
|
328
|
-
},
|
|
329
|
-
onloadstart(...args) {
|
|
330
|
-
that.context.HttpxResponseCallBack.onLoadStart(userRequestOption as Required<HttpxRequestOption>, args);
|
|
331
|
-
},
|
|
332
|
-
onprogress(...args) {
|
|
333
|
-
that.context.HttpxResponseCallBack.onProgress(userRequestOption as Required<HttpxRequestOption>, args);
|
|
334
|
-
},
|
|
335
|
-
onreadystatechange(...args) {
|
|
336
|
-
that.context.HttpxResponseCallBack.onReadyStateChange(
|
|
337
|
-
userRequestOption as Required<HttpxRequestOption>,
|
|
338
|
-
args
|
|
339
|
-
);
|
|
340
|
-
},
|
|
341
|
-
ontimeout(...args) {
|
|
342
|
-
that.context.HttpxResponseCallBack.onTimeout(
|
|
343
|
-
userRequestOption as Required<HttpxRequestOption>,
|
|
344
|
-
resolve,
|
|
345
|
-
reject,
|
|
346
|
-
args
|
|
347
|
-
);
|
|
348
|
-
},
|
|
349
|
-
onload(...args) {
|
|
350
|
-
that.context.HttpxResponseCallBack.onLoad(
|
|
351
|
-
userRequestOption as Required<HttpxRequestOption>,
|
|
352
|
-
resolve,
|
|
353
|
-
reject,
|
|
354
|
-
args
|
|
355
|
-
);
|
|
356
|
-
},
|
|
357
|
-
};
|
|
358
|
-
// 补全allowInterceptConfig参数
|
|
359
|
-
if (typeof userRequestOption.allowInterceptConfig === "boolean") {
|
|
360
|
-
const allowInterceptConfigKeys = Object.keys(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig);
|
|
361
|
-
allowInterceptConfigKeys.forEach((keyName) => {
|
|
362
|
-
Reflect.set(
|
|
363
|
-
requestOption.allowInterceptConfig as HttpxAllowInterceptConfig,
|
|
364
|
-
keyName,
|
|
365
|
-
userRequestOption.allowInterceptConfig
|
|
366
|
-
);
|
|
367
|
-
});
|
|
368
|
-
} else {
|
|
369
|
-
if (
|
|
370
|
-
typeof userRequestOption.allowInterceptConfig === "object" &&
|
|
371
|
-
userRequestOption.allowInterceptConfig != null
|
|
372
|
-
) {
|
|
373
|
-
const allowInterceptConfigKeys = Object.keys(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig);
|
|
374
|
-
allowInterceptConfigKeys.forEach((keyName) => {
|
|
375
|
-
const value = Reflect.get(
|
|
376
|
-
userRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig,
|
|
377
|
-
keyName
|
|
378
|
-
) as boolean;
|
|
379
|
-
if (
|
|
380
|
-
typeof value === "boolean" &&
|
|
381
|
-
Reflect.has(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig, keyName)
|
|
382
|
-
) {
|
|
383
|
-
Reflect.set(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig, keyName, value);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
if (typeof this.context.GM_Api.xmlHttpRequest !== "function") {
|
|
389
|
-
// GM函数不存在,强制使用fetch
|
|
390
|
-
requestOption.fetch = true;
|
|
391
|
-
}
|
|
392
|
-
if (typeof requestOption.headers === "object") {
|
|
393
|
-
if (typeof userRequestOption.headers === "object") {
|
|
394
|
-
const headerKeys = Object.keys(requestOption.headers);
|
|
395
|
-
headerKeys.forEach((keyName) => {
|
|
396
|
-
if (keyName in requestOption.headers && userRequestOption!.headers?.[keyName] == null) {
|
|
397
|
-
/* 在默认的header中存在,且设置它新的值为空,那么就是默认的值 */
|
|
398
|
-
Reflect.deleteProperty(requestOption.headers, keyName);
|
|
399
|
-
} else {
|
|
400
|
-
requestOption.headers[keyName] = userRequestOption?.headers?.[keyName];
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
} else {
|
|
404
|
-
/* details.headers为空 */
|
|
405
|
-
/* 不做处理 */
|
|
406
|
-
}
|
|
407
|
-
} else {
|
|
408
|
-
/* 默认的headers不是对象,那么就直接使用新的 */
|
|
409
|
-
Reflect.set(requestOption, "headers", userRequestOption.headers);
|
|
410
|
-
}
|
|
411
|
-
if (typeof requestOption.fetchInit === "object") {
|
|
412
|
-
/* 使用assign替换且添加 */
|
|
413
|
-
if (typeof userRequestOption.fetchInit === "object") {
|
|
414
|
-
const fetchInitKeys = Object.keys(requestOption.fetchInit);
|
|
415
|
-
fetchInitKeys.forEach((keyName) => {
|
|
416
|
-
if (keyName in requestOption.fetchInit && Reflect.get(userRequestOption.fetchInit ?? {}, keyName) == null) {
|
|
417
|
-
/* 在默认的fetchInit中存在,且设置它新的值为空,那么就是默认的值 */
|
|
418
|
-
Reflect.deleteProperty(requestOption.fetchInit, keyName);
|
|
419
|
-
} else {
|
|
420
|
-
Reflect.set(requestOption.fetchInit, keyName, Reflect.get(userRequestOption.fetchInit!, keyName));
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
} else {
|
|
425
|
-
Reflect.set(requestOption, "fetchInit", userRequestOption.fetchInit);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// 处理新的cookiePartition
|
|
429
|
-
if (typeof requestOption.cookiePartition === "object" && requestOption.cookiePartition != null) {
|
|
430
|
-
if (
|
|
431
|
-
Reflect.has(requestOption.cookiePartition, "topLevelSite") &&
|
|
432
|
-
typeof requestOption.cookiePartition.topLevelSite !== "string"
|
|
433
|
-
) {
|
|
434
|
-
// topLevelSite必须是字符串
|
|
435
|
-
Reflect.deleteProperty(requestOption.cookiePartition, "topLevelSite");
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/* 完善请求的url */
|
|
440
|
-
try {
|
|
441
|
-
new URL(requestOption.url);
|
|
442
|
-
} catch {
|
|
443
|
-
if (requestOption.url.startsWith("//")) {
|
|
444
|
-
// 补充https:
|
|
445
|
-
requestOption.url = globalThis.location.protocol + requestOption.url;
|
|
446
|
-
} else if (requestOption.url.startsWith("/")) {
|
|
447
|
-
// 补充origin
|
|
448
|
-
requestOption.url = globalThis.location.origin + requestOption.url;
|
|
449
|
-
} else {
|
|
450
|
-
// 补充origin+/
|
|
451
|
-
requestOption.url = `${globalThis.location.origin}/${requestOption.url}`;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
if (requestOption.fetchInit && !requestOption.fetch) {
|
|
456
|
-
// 清空fetchInit
|
|
457
|
-
Reflect.deleteProperty(requestOption, "fetchInit");
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// 转换data类型
|
|
461
|
-
try {
|
|
462
|
-
/** 是否对数据进行处理 */
|
|
463
|
-
const processData = userRequestOption.processData ?? true;
|
|
464
|
-
if (requestOption.data != null && processData) {
|
|
465
|
-
const method = requestOption.method;
|
|
466
|
-
if (method === "GET" || method === "HEAD") {
|
|
467
|
-
// GET类型,data如果有,那么需要转为searchParams
|
|
468
|
-
const urlObj = new URL(requestOption.url);
|
|
469
|
-
let urlSearch = "";
|
|
470
|
-
let isHandler = false;
|
|
471
|
-
if (typeof requestOption.data === "string") {
|
|
472
|
-
isHandler = true;
|
|
473
|
-
urlSearch = requestOption.data;
|
|
474
|
-
} else if (typeof requestOption.data === "object") {
|
|
475
|
-
isHandler = true;
|
|
476
|
-
// URLSearchParams参数可以转普通的string:string,包括FormData
|
|
477
|
-
const searchParams = new URLSearchParams(requestOption.data as Record<string, string>);
|
|
478
|
-
urlSearch = searchParams.toString();
|
|
479
|
-
}
|
|
480
|
-
if (isHandler) {
|
|
481
|
-
// GET/HEAD请求不支持data参数
|
|
482
|
-
// 对data进行处理了才可以删除
|
|
483
|
-
Reflect.deleteProperty(requestOption, "data");
|
|
484
|
-
}
|
|
485
|
-
if (urlSearch != "") {
|
|
486
|
-
if (urlObj.search === "") {
|
|
487
|
-
// url没有search参数,直接覆盖
|
|
488
|
-
urlObj.search = urlSearch;
|
|
489
|
-
} else {
|
|
490
|
-
// 有search参数
|
|
491
|
-
if (urlObj.search.endsWith("&")) {
|
|
492
|
-
// xxx=xxx&
|
|
493
|
-
urlObj.search = urlObj.search + urlSearch;
|
|
494
|
-
} else {
|
|
495
|
-
// xxx=xxx&xxx=
|
|
496
|
-
urlObj.search = `${urlObj.search}&${urlSearch}`;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
requestOption.url = urlObj.toString();
|
|
501
|
-
} else if (method === "POST" && requestOption.headers != null) {
|
|
502
|
-
// POST类型,data如果是FormData,那么需要转为string
|
|
503
|
-
const headersKeyList = Object.keys(requestOption.headers);
|
|
504
|
-
const ContentTypeIndex = headersKeyList.findIndex((headerKey) => {
|
|
505
|
-
return (
|
|
506
|
-
headerKey.trim().toLowerCase() === "content-type" &&
|
|
507
|
-
typeof requestOption.headers[headerKey] === "string"
|
|
508
|
-
);
|
|
509
|
-
});
|
|
510
|
-
if (ContentTypeIndex !== -1) {
|
|
511
|
-
const ContentTypeKey = headersKeyList[ContentTypeIndex];
|
|
512
|
-
const ContentType = requestOption.headers[ContentTypeKey] as string;
|
|
513
|
-
// 设置了Content-Type
|
|
514
|
-
if (ContentType.includes("application/json")) {
|
|
515
|
-
// application/json
|
|
516
|
-
if (requestOption.data instanceof FormData) {
|
|
517
|
-
const entries: { [key: string]: any } = {};
|
|
518
|
-
requestOption.data.forEach((value, key) => {
|
|
519
|
-
entries[key] = value;
|
|
520
|
-
});
|
|
521
|
-
requestOption.data = JSON.stringify(entries);
|
|
522
|
-
} else if (typeof requestOption.data === "object") {
|
|
523
|
-
requestOption.data = JSON.stringify(requestOption.data);
|
|
524
|
-
}
|
|
525
|
-
} else if (ContentType.includes("application/x-www-form-urlencoded")) {
|
|
526
|
-
// application/x-www-form-urlencoded
|
|
527
|
-
if (typeof requestOption.data === "object") {
|
|
528
|
-
requestOption.data = new URLSearchParams(requestOption.data as Record<string, string>).toString();
|
|
529
|
-
}
|
|
530
|
-
} else if (ContentType.includes("multipart/form-data")) {
|
|
531
|
-
// multipart/form-data
|
|
532
|
-
if (requestOption.data instanceof FormData) {
|
|
533
|
-
Reflect.deleteProperty(requestOption.headers, ContentTypeKey);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
} catch (error) {
|
|
540
|
-
console.warn("Httpx ==> 转换data参数错误", error);
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
return requestOption;
|
|
544
|
-
},
|
|
545
|
-
/**
|
|
546
|
-
* 处理发送请求的配置,去除值为undefined、空function的值
|
|
547
|
-
* @param option 请求配置
|
|
548
|
-
*/
|
|
549
|
-
removeRequestNullOption(option: Required<HttpxRequestOption>): Required<HttpxRequestOption> {
|
|
550
|
-
const optionKeys = Object.keys(option);
|
|
551
|
-
optionKeys.forEach((keyName) => {
|
|
552
|
-
const optionValue = option[keyName as keyof HttpxRequestOption];
|
|
553
|
-
if (optionValue == null || (optionValue instanceof Function && CommonUtil.isNull(optionValue))) {
|
|
554
|
-
Reflect.deleteProperty(option, keyName);
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
if (CommonUtil.isNull(option.url)) {
|
|
559
|
-
throw new TypeError(`Utils.Httpx 参数url不能为空:${option.url}`);
|
|
560
|
-
}
|
|
561
|
-
return option;
|
|
562
|
-
},
|
|
563
|
-
/**
|
|
564
|
-
* 处理fetch的配置
|
|
565
|
-
* @param option 请求配置
|
|
566
|
-
*/
|
|
567
|
-
handleFetchOption(option: Required<HttpxRequestOption>) {
|
|
568
|
-
/**
|
|
569
|
-
* fetch的请求配置
|
|
570
|
-
**/
|
|
571
|
-
const fetchRequestOption = <RequestInit>{};
|
|
572
|
-
if ((option.method === "GET" || option.method === "HEAD") && option.data != null) {
|
|
573
|
-
/* GET 或 HEAD 方法的请求不能包含 body 信息 */
|
|
574
|
-
Reflect.deleteProperty(option, "data");
|
|
575
|
-
}
|
|
576
|
-
/* 中止信号控制器 */
|
|
577
|
-
const abortController = new AbortController();
|
|
578
|
-
const signal = abortController.signal;
|
|
579
|
-
signal.onabort = () => {
|
|
580
|
-
option.onabort({
|
|
581
|
-
isFetch: true,
|
|
582
|
-
responseText: "",
|
|
583
|
-
response: null,
|
|
584
|
-
readyState: 4,
|
|
585
|
-
responseHeaders: "",
|
|
586
|
-
status: 0,
|
|
587
|
-
statusText: "",
|
|
588
|
-
error: "aborted",
|
|
589
|
-
});
|
|
590
|
-
};
|
|
591
|
-
// 设置请求
|
|
592
|
-
fetchRequestOption.method = option.method ?? "GET";
|
|
593
|
-
// 设置请求头
|
|
594
|
-
fetchRequestOption.headers = option.headers;
|
|
595
|
-
// 设置请求体
|
|
596
|
-
fetchRequestOption.body = option.data as string | FormData;
|
|
597
|
-
// 设置跨域
|
|
598
|
-
fetchRequestOption.mode = "cors";
|
|
599
|
-
// 设置包含
|
|
600
|
-
fetchRequestOption.credentials = "include";
|
|
601
|
-
// 设置不缓存
|
|
602
|
-
fetchRequestOption.cache = "no-cache";
|
|
603
|
-
// 设置始终重定向
|
|
604
|
-
fetchRequestOption.redirect = "follow";
|
|
605
|
-
// 设置referer跨域
|
|
606
|
-
fetchRequestOption.referrerPolicy = "origin-when-cross-origin";
|
|
607
|
-
// 设置信号中断
|
|
608
|
-
fetchRequestOption.signal = signal;
|
|
609
|
-
Object.assign(fetchRequestOption, option.fetchInit || {});
|
|
610
|
-
return {
|
|
611
|
-
fetchOption: option,
|
|
612
|
-
fetchRequestOption: fetchRequestOption,
|
|
613
|
-
abortController: abortController,
|
|
614
|
-
};
|
|
615
|
-
},
|
|
616
|
-
};
|
|
617
|
-
private HttpxResponseCallBack = {
|
|
618
|
-
context: this,
|
|
619
|
-
/**
|
|
620
|
-
* onabort请求被取消-触发
|
|
621
|
-
* @param details 配置
|
|
622
|
-
* @param resolve promise回调
|
|
623
|
-
* @param _reject promise抛出错误回调
|
|
624
|
-
* @param argsResult 返回的参数列表
|
|
625
|
-
*/
|
|
626
|
-
async onAbort(
|
|
627
|
-
details: Required<HttpxRequestOption>,
|
|
628
|
-
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
629
|
-
_reject: (...args: any[]) => void,
|
|
630
|
-
argsResult: any
|
|
631
|
-
) {
|
|
632
|
-
// console.log(argsResult);
|
|
633
|
-
if (typeof details?.onabort === "function") {
|
|
634
|
-
details.onabort.apply(this, argsResult);
|
|
635
|
-
} else if (typeof this.context.#defaultRequestOption?.onabort === "function") {
|
|
636
|
-
this.context.#defaultRequestOption.onabort.apply(this, argsResult);
|
|
637
|
-
}
|
|
638
|
-
let response = argsResult;
|
|
639
|
-
if (response.length) {
|
|
640
|
-
response = response[0];
|
|
641
|
-
}
|
|
642
|
-
if (
|
|
643
|
-
(await this.context.HttpxResponseHook.errorResponseCallBack({
|
|
644
|
-
type: "onabort",
|
|
645
|
-
error: new Error("request canceled"),
|
|
646
|
-
response: null,
|
|
647
|
-
details: details,
|
|
648
|
-
})) == null
|
|
649
|
-
) {
|
|
650
|
-
// reject(new Error("response is intercept with onabort"));
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
resolve({
|
|
654
|
-
data: response,
|
|
655
|
-
details: details,
|
|
656
|
-
msg: "请求被取消",
|
|
657
|
-
status: false,
|
|
658
|
-
statusCode: -1,
|
|
659
|
-
type: "onabort",
|
|
660
|
-
});
|
|
661
|
-
},
|
|
662
|
-
/**
|
|
663
|
-
* ontimeout请求超时-触发
|
|
664
|
-
* @param details 配置
|
|
665
|
-
* @param resolve 回调
|
|
666
|
-
* @param reject 抛出错误
|
|
667
|
-
* @param argsResult 返回的参数列表
|
|
668
|
-
*/
|
|
669
|
-
async onTimeout(
|
|
670
|
-
details: Required<HttpxRequestOption>,
|
|
671
|
-
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
672
|
-
_reject: (...args: any[]) => void,
|
|
673
|
-
argsResult: any
|
|
674
|
-
) {
|
|
675
|
-
// console.log(argsResult);
|
|
676
|
-
if (typeof details?.ontimeout === "function") {
|
|
677
|
-
// 执行配置中的ontime回调
|
|
678
|
-
details.ontimeout.apply(this, argsResult);
|
|
679
|
-
} else if (typeof this.context.#defaultRequestOption?.ontimeout === "function") {
|
|
680
|
-
// 执行默认配置的ontime回调
|
|
681
|
-
this.context.#defaultRequestOption.ontimeout.apply(this, argsResult);
|
|
682
|
-
}
|
|
683
|
-
// 获取响应结果
|
|
684
|
-
let response = argsResult;
|
|
685
|
-
if (response.length) {
|
|
686
|
-
response = response[0];
|
|
687
|
-
}
|
|
688
|
-
// 执行错误回调的钩子
|
|
689
|
-
if (
|
|
690
|
-
(await this.context.HttpxResponseHook.errorResponseCallBack({
|
|
691
|
-
type: "ontimeout",
|
|
692
|
-
error: new Error("request timeout"),
|
|
693
|
-
response: response,
|
|
694
|
-
details: details,
|
|
695
|
-
})) == null
|
|
696
|
-
) {
|
|
697
|
-
// reject(new Error("response is intercept with ontimeout"));
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
resolve({
|
|
701
|
-
data: response,
|
|
702
|
-
details: details,
|
|
703
|
-
msg: "请求超时",
|
|
704
|
-
status: false,
|
|
705
|
-
statusCode: 0,
|
|
706
|
-
type: "ontimeout",
|
|
707
|
-
});
|
|
708
|
-
},
|
|
709
|
-
/**
|
|
710
|
-
* onerror请求异常-触发
|
|
711
|
-
* @param details 配置
|
|
712
|
-
* @param resolve 回调
|
|
713
|
-
* @param _reject 抛出错误
|
|
714
|
-
* @param argsResult 返回的参数列表
|
|
715
|
-
*/
|
|
716
|
-
async onError(
|
|
717
|
-
details: Required<HttpxRequestOption>,
|
|
718
|
-
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
719
|
-
_reject: (...args: any[]) => void,
|
|
720
|
-
argsResult: any
|
|
721
|
-
) {
|
|
722
|
-
// console.log(argsResult);
|
|
723
|
-
if (typeof details?.onerror === "function") {
|
|
724
|
-
details.onerror.apply(this, argsResult);
|
|
725
|
-
} else if (typeof this.context.#defaultRequestOption?.onerror === "function") {
|
|
726
|
-
this.context.#defaultRequestOption.onerror.apply(this, argsResult);
|
|
727
|
-
}
|
|
728
|
-
let response = argsResult;
|
|
729
|
-
if (response.length) {
|
|
730
|
-
response = response[0];
|
|
731
|
-
}
|
|
732
|
-
if (
|
|
733
|
-
(await this.context.HttpxResponseHook.errorResponseCallBack({
|
|
734
|
-
type: "onerror",
|
|
735
|
-
error: new Error("request error"),
|
|
736
|
-
response: response,
|
|
737
|
-
details: details,
|
|
738
|
-
})) == null
|
|
739
|
-
) {
|
|
740
|
-
// reject(new Error("response is intercept with onerror"));
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
resolve({
|
|
744
|
-
data: response,
|
|
745
|
-
details: details,
|
|
746
|
-
msg: "请求异常",
|
|
747
|
-
status: false,
|
|
748
|
-
statusCode: response["status"],
|
|
749
|
-
type: "onerror",
|
|
750
|
-
});
|
|
751
|
-
},
|
|
752
|
-
/**
|
|
753
|
-
* onload加载完毕-触发
|
|
754
|
-
* @param details 请求的配置
|
|
755
|
-
* @param resolve 回调
|
|
756
|
-
* @param _reject 抛出错误
|
|
757
|
-
* @param argsResult 返回的参数列表
|
|
758
|
-
*/
|
|
759
|
-
async onLoad(
|
|
760
|
-
details: Required<HttpxRequestOption>,
|
|
761
|
-
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
762
|
-
_reject: (...args: any[]) => void,
|
|
763
|
-
argsResult: any[]
|
|
764
|
-
) {
|
|
765
|
-
// console.log(argsResult);
|
|
766
|
-
/* X浏览器会因为设置了responseType导致不返回responseText */
|
|
767
|
-
const originResponse: HttpxResponseData<HttpxRequestOption> = argsResult[0];
|
|
768
|
-
/* responseText为空,response不为空的情况 */
|
|
769
|
-
if (CommonUtil.isNull(originResponse["responseText"]) && CommonUtil.isNotNull(originResponse["response"])) {
|
|
770
|
-
if (typeof originResponse["response"] === "object") {
|
|
771
|
-
TryCatch().run(() => {
|
|
772
|
-
originResponse["responseText"] = JSON.stringify(originResponse["response"]);
|
|
773
|
-
});
|
|
774
|
-
} else {
|
|
775
|
-
originResponse["responseText"] = originResponse["response"] as string;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
/* response为空,responseText不为空的情况 */
|
|
780
|
-
if (
|
|
781
|
-
originResponse["response"] == null &&
|
|
782
|
-
typeof originResponse["responseText"] === "string" &&
|
|
783
|
-
originResponse["responseText"].trim() !== ""
|
|
784
|
-
) {
|
|
785
|
-
/** 原始的请求text */
|
|
786
|
-
const httpxResponseText = originResponse.responseText;
|
|
787
|
-
// 自定义个新的response
|
|
788
|
-
let httpxResponse: any = httpxResponseText;
|
|
789
|
-
if (details.responseType === "json") {
|
|
790
|
-
httpxResponse = CommonUtil.toJSON(httpxResponseText);
|
|
791
|
-
} else if (details.responseType === "document") {
|
|
792
|
-
const parser = new DOMParser();
|
|
793
|
-
httpxResponse = parser.parseFromString(httpxResponseText, "text/html");
|
|
794
|
-
} else if (details.responseType === "arraybuffer") {
|
|
795
|
-
const encoder = new TextEncoder();
|
|
796
|
-
const arrayBuffer = encoder.encode(httpxResponseText);
|
|
797
|
-
httpxResponse = arrayBuffer;
|
|
798
|
-
} else if (details.responseType === "blob") {
|
|
799
|
-
const encoder = new TextEncoder();
|
|
800
|
-
const arrayBuffer = encoder.encode(httpxResponseText);
|
|
801
|
-
httpxResponse = new Blob([arrayBuffer]);
|
|
802
|
-
}
|
|
803
|
-
// 尝试覆盖原response
|
|
804
|
-
try {
|
|
805
|
-
const setStatus = Reflect.set(originResponse, "response", httpxResponse);
|
|
806
|
-
if (!setStatus) {
|
|
807
|
-
console.warn("[Httpx-HttpxCallBack.oonLoad] 覆盖原始 response 失败,尝试添加新的httpxResponse");
|
|
808
|
-
try {
|
|
809
|
-
Reflect.set(originResponse, "httpxResponse", httpxResponse);
|
|
810
|
-
} catch {
|
|
811
|
-
console.warn("[Httpx-HttpxCallBack.oonLoad] httpxResponse 无法被覆盖");
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
} catch {
|
|
815
|
-
console.warn("[Httpx-HttpxCallBack.oonLoad] 原始 response 无法被覆盖,尝试添加新的httpxResponse");
|
|
816
|
-
try {
|
|
817
|
-
Reflect.set(originResponse, "httpxResponse", httpxResponse);
|
|
818
|
-
} catch {
|
|
819
|
-
console.warn("[Httpx-HttpxCallBack.oonLoad] httpxResponse 无法被覆盖");
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
/* Stay扩展中没有finalUrl,对应的是responseURL */
|
|
824
|
-
const originResponseURL = Reflect.get(originResponse, "responseURL");
|
|
825
|
-
if (originResponse["finalUrl"] == null && originResponseURL != null) {
|
|
826
|
-
Reflect.set(originResponse, "finalUrl", originResponseURL);
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
/* 状态码2xx都是成功的 */
|
|
830
|
-
if (Math.floor(originResponse.status / 100) === 2) {
|
|
831
|
-
if ((await this.context.HttpxResponseHook.successResponseCallBack(originResponse, details)) == null) {
|
|
832
|
-
// reject(new Error("response is intercept with onloada"));
|
|
833
|
-
return;
|
|
834
|
-
}
|
|
835
|
-
resolve({
|
|
836
|
-
data: originResponse,
|
|
837
|
-
details: details,
|
|
838
|
-
msg: "请求成功",
|
|
839
|
-
status: true,
|
|
840
|
-
statusCode: originResponse.status,
|
|
841
|
-
type: "onload",
|
|
842
|
-
});
|
|
843
|
-
} else {
|
|
844
|
-
this.context.HttpxResponseCallBack.onError(details, resolve, _reject, argsResult);
|
|
845
|
-
}
|
|
846
|
-
},
|
|
847
|
-
/**
|
|
848
|
-
* onloadstart请求开始-触发
|
|
849
|
-
* @param details 配置
|
|
850
|
-
* @param argsResult 返回的参数列表
|
|
851
|
-
*/
|
|
852
|
-
onLoadStart(details: Required<HttpxRequestOption>, argsResult: any[]) {
|
|
853
|
-
// console.log(argsResult);
|
|
854
|
-
if (typeof details?.onloadstart === "function") {
|
|
855
|
-
details.onloadstart.apply(this, argsResult);
|
|
856
|
-
} else if (typeof this.context.#defaultRequestOption?.onloadstart === "function") {
|
|
857
|
-
this.context.#defaultRequestOption.onloadstart.apply(this, argsResult);
|
|
858
|
-
}
|
|
859
|
-
},
|
|
860
|
-
/**
|
|
861
|
-
* onreadystatechange准备状态改变-触发
|
|
862
|
-
* @param details 配置
|
|
863
|
-
* @param argsResult 返回的参数列表
|
|
864
|
-
*/
|
|
865
|
-
onReadyStateChange(details: Required<HttpxRequestOption>, argsResult: any[]) {
|
|
866
|
-
// console.log(argsResult);
|
|
867
|
-
if (typeof details?.onreadystatechange === "function") {
|
|
868
|
-
details.onreadystatechange.apply(this, argsResult);
|
|
869
|
-
} else if (typeof this.context.#defaultRequestOption?.onreadystatechange === "function") {
|
|
870
|
-
this.context.#defaultRequestOption.onreadystatechange.apply(this, argsResult);
|
|
871
|
-
}
|
|
872
|
-
},
|
|
873
|
-
/**
|
|
874
|
-
* onprogress上传进度-触发
|
|
875
|
-
* @param details 配置
|
|
876
|
-
* @param argsResult 返回的参数列表
|
|
877
|
-
*/
|
|
878
|
-
onProgress(details: Required<HttpxRequestOption>, argsResult: any[]) {
|
|
879
|
-
// console.log(argsResult);
|
|
880
|
-
if (typeof details?.onprogress === "function") {
|
|
881
|
-
details.onprogress.apply(this, argsResult);
|
|
882
|
-
} else if (typeof this.context.#defaultRequestOption?.onprogress === "function") {
|
|
883
|
-
this.context.#defaultRequestOption.onprogress.apply(this, argsResult);
|
|
884
|
-
}
|
|
885
|
-
},
|
|
886
|
-
};
|
|
887
|
-
private HttpxRequest = {
|
|
888
|
-
context: this,
|
|
889
|
-
/**
|
|
890
|
-
* 发送请求
|
|
891
|
-
* @param details
|
|
892
|
-
*/
|
|
893
|
-
async request(details: Required<HttpxRequestOption>) {
|
|
894
|
-
if (this.context.#defaultInitOption.logDetails) {
|
|
895
|
-
console.log("[Httpx-HttpxRequest.request] 请求前的配置👇", details);
|
|
896
|
-
}
|
|
897
|
-
if (typeof this.context.HttpxRequestHook.beforeRequestCallBack === "function") {
|
|
898
|
-
const hookResult = await this.context.HttpxRequestHook.beforeRequestCallBack(details);
|
|
899
|
-
if (hookResult == null) {
|
|
900
|
-
return;
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
if (details.fetch) {
|
|
904
|
-
// 使用fetch请求
|
|
905
|
-
const {
|
|
906
|
-
fetchOption: fetchOption,
|
|
907
|
-
fetchRequestOption: fetchRequestOption,
|
|
908
|
-
abortController,
|
|
909
|
-
} = this.context.HttpxRequestOption.handleFetchOption(details);
|
|
910
|
-
return this.fetch(fetchOption, fetchRequestOption, abortController);
|
|
911
|
-
} else {
|
|
912
|
-
// 使用GM_xmlHttpRequest请求
|
|
913
|
-
return this.xmlHttpRequest(details);
|
|
914
|
-
}
|
|
915
|
-
},
|
|
916
|
-
/**
|
|
917
|
-
* 使用油猴函数GM_xmlhttpRequest发送请求
|
|
918
|
-
* @param details
|
|
919
|
-
*/
|
|
920
|
-
xmlHttpRequest(details: Required<HttpxRequestOption>) {
|
|
921
|
-
return this.context.GM_Api.xmlHttpRequest!(details) as {
|
|
922
|
-
abort: () => void;
|
|
923
|
-
};
|
|
924
|
-
},
|
|
925
|
-
/**
|
|
926
|
-
* 使用fetch发送请求
|
|
927
|
-
* @param option
|
|
928
|
-
* @param fetchRequestOption
|
|
929
|
-
* @param abortController
|
|
930
|
-
*/
|
|
931
|
-
fetch(option: Required<HttpxRequestOption>, fetchRequestOption: RequestInit, abortController: AbortController) {
|
|
932
|
-
fetch(option.url, fetchRequestOption)
|
|
933
|
-
.then(async (fetchResponse) => {
|
|
934
|
-
/** 自定义的response */
|
|
935
|
-
const httpxResponse: HttpxResponseData<HttpxRequestOption> = {
|
|
936
|
-
isFetch: true,
|
|
937
|
-
finalUrl: fetchResponse.url,
|
|
938
|
-
readyState: 4,
|
|
939
|
-
status: fetchResponse.status,
|
|
940
|
-
statusText: fetchResponse.statusText,
|
|
941
|
-
response: "",
|
|
942
|
-
responseFetchHeaders: fetchResponse.headers,
|
|
943
|
-
responseHeaders: "",
|
|
944
|
-
responseText: "",
|
|
945
|
-
responseType: option.responseType,
|
|
946
|
-
responseXML: void 0,
|
|
947
|
-
};
|
|
948
|
-
Object.assign(httpxResponse, option.context || {});
|
|
949
|
-
|
|
950
|
-
// 把headers转为字符串
|
|
951
|
-
fetchResponse.headers.forEach((value, key) => {
|
|
952
|
-
httpxResponse.responseHeaders += `${key}: ${value}\n`;
|
|
953
|
-
});
|
|
954
|
-
|
|
955
|
-
/** 请求返回的类型 */
|
|
956
|
-
const fetchResponseType = fetchResponse.headers.get("Content-Type");
|
|
957
|
-
|
|
958
|
-
/* 如果需要stream,且获取到的是stream,那直接返回 */
|
|
959
|
-
if (
|
|
960
|
-
option.responseType === "stream" ||
|
|
961
|
-
(fetchResponse.headers.has("Content-Type") &&
|
|
962
|
-
fetchResponse.headers.get("Content-Type")!.includes("text/event-stream"))
|
|
963
|
-
) {
|
|
964
|
-
Reflect.set(httpxResponse, "isStream", true);
|
|
965
|
-
Reflect.set(httpxResponse, "response", fetchResponse.body);
|
|
966
|
-
Reflect.deleteProperty(httpxResponse, "responseText");
|
|
967
|
-
Reflect.deleteProperty(httpxResponse, "responseXML");
|
|
968
|
-
option.onload(httpxResponse);
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
/** 响应 */
|
|
973
|
-
let response: any = "";
|
|
974
|
-
/** 响应字符串 */
|
|
975
|
-
let responseText: string = "";
|
|
976
|
-
/** 响应xml文档 */
|
|
977
|
-
let responseXML: XMLDocument | string = "";
|
|
978
|
-
/** 先获取二进制数据 */
|
|
979
|
-
const arrayBuffer = await fetchResponse.arrayBuffer();
|
|
980
|
-
|
|
981
|
-
/** 数据编码 */
|
|
982
|
-
let encoding = "utf-8";
|
|
983
|
-
if (fetchResponse.headers.has("Content-Type")) {
|
|
984
|
-
const charsetMatched = fetchResponse.headers.get("Content-Type")?.match(/charset=(.+)/);
|
|
985
|
-
if (charsetMatched) {
|
|
986
|
-
encoding = charsetMatched[1];
|
|
987
|
-
encoding = encoding.toLowerCase();
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
// Failed to construct 'TextDecoder': The encoding label provided ('"UTF-8"') is invalid.
|
|
991
|
-
// 去除引号
|
|
992
|
-
encoding = encoding.replace(/('|")/gi, "");
|
|
993
|
-
// 编码
|
|
994
|
-
const textDecoder = new TextDecoder(encoding);
|
|
995
|
-
responseText = textDecoder.decode(arrayBuffer);
|
|
996
|
-
response = responseText;
|
|
997
|
-
|
|
998
|
-
if (option.responseType === "arraybuffer") {
|
|
999
|
-
// response返回格式是二进制流
|
|
1000
|
-
response = arrayBuffer;
|
|
1001
|
-
} else if (option.responseType === "blob") {
|
|
1002
|
-
// response返回格式是blob
|
|
1003
|
-
response = new Blob([arrayBuffer]);
|
|
1004
|
-
} else if (
|
|
1005
|
-
option.responseType === "json" ||
|
|
1006
|
-
(typeof fetchResponseType === "string" && fetchResponseType.includes("application/json"))
|
|
1007
|
-
) {
|
|
1008
|
-
// response返回格式是JSON格式
|
|
1009
|
-
response = CommonUtil.toJSON(responseText);
|
|
1010
|
-
} else if (option.responseType === "document" || option.responseType == null) {
|
|
1011
|
-
// response返回格式是文档格式
|
|
1012
|
-
const parser = new DOMParser();
|
|
1013
|
-
response = parser.parseFromString(responseText, "text/html");
|
|
1014
|
-
}
|
|
1015
|
-
// 转为XML结构
|
|
1016
|
-
const parser = new DOMParser();
|
|
1017
|
-
responseXML = parser.parseFromString(responseText, "text/xml");
|
|
1018
|
-
|
|
1019
|
-
httpxResponse.response = response;
|
|
1020
|
-
httpxResponse.responseText = responseText;
|
|
1021
|
-
httpxResponse.responseXML = responseXML;
|
|
1022
|
-
|
|
1023
|
-
// 执行回调
|
|
1024
|
-
option.onload(httpxResponse);
|
|
1025
|
-
})
|
|
1026
|
-
.catch((error: any) => {
|
|
1027
|
-
if (error.name === "AbortError") {
|
|
1028
|
-
return;
|
|
1029
|
-
}
|
|
1030
|
-
option.onerror({
|
|
1031
|
-
isFetch: true,
|
|
1032
|
-
finalUrl: option.url,
|
|
1033
|
-
readyState: 4,
|
|
1034
|
-
status: 0,
|
|
1035
|
-
statusText: "",
|
|
1036
|
-
responseHeaders: "",
|
|
1037
|
-
responseText: "",
|
|
1038
|
-
error: error,
|
|
1039
|
-
});
|
|
1040
|
-
});
|
|
1041
|
-
option.onloadstart({
|
|
1042
|
-
isFetch: true,
|
|
1043
|
-
finalUrl: option.url,
|
|
1044
|
-
readyState: 1,
|
|
1045
|
-
responseHeaders: "",
|
|
1046
|
-
responseText: "",
|
|
1047
|
-
status: 0,
|
|
1048
|
-
statusText: "",
|
|
1049
|
-
});
|
|
1050
|
-
return {
|
|
1051
|
-
abort() {
|
|
1052
|
-
abortController.abort();
|
|
1053
|
-
},
|
|
1054
|
-
};
|
|
1055
|
-
},
|
|
1056
|
-
};
|
|
1057
|
-
/**
|
|
1058
|
-
* 默认配置
|
|
1059
|
-
*/
|
|
1060
|
-
#defaultRequestOption = <HttpxRequestOption>{
|
|
1061
|
-
url: void 0 as undefined | string,
|
|
1062
|
-
timeout: 5000,
|
|
1063
|
-
async: false,
|
|
1064
|
-
responseType: void 0,
|
|
1065
|
-
headers: void 0,
|
|
1066
|
-
data: void 0,
|
|
1067
|
-
redirect: void 0,
|
|
1068
|
-
cookie: void 0,
|
|
1069
|
-
cookiePartition: void 0,
|
|
1070
|
-
binary: void 0,
|
|
1071
|
-
nocache: void 0,
|
|
1072
|
-
revalidate: void 0,
|
|
1073
|
-
context: void 0,
|
|
1074
|
-
overrideMimeType: void 0,
|
|
1075
|
-
anonymous: void 0,
|
|
1076
|
-
fetch: void 0,
|
|
1077
|
-
fetchInit: void 0,
|
|
1078
|
-
allowInterceptConfig: {
|
|
1079
|
-
beforeRequest: true,
|
|
1080
|
-
afterResponseSuccess: true,
|
|
1081
|
-
afterResponseError: true,
|
|
1082
|
-
},
|
|
1083
|
-
user: void 0,
|
|
1084
|
-
password: void 0,
|
|
1085
|
-
onabort() {},
|
|
1086
|
-
onerror() {},
|
|
1087
|
-
ontimeout() {},
|
|
1088
|
-
onloadstart() {},
|
|
1089
|
-
onreadystatechange() {},
|
|
1090
|
-
onprogress() {},
|
|
1091
|
-
};
|
|
1092
|
-
/**
|
|
1093
|
-
* 实例化的默认配置
|
|
1094
|
-
*/
|
|
1095
|
-
#defaultInitOption = {
|
|
1096
|
-
/**
|
|
1097
|
-
* `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
|
|
1098
|
-
*/
|
|
1099
|
-
baseURL: void 0 as undefined | string,
|
|
1100
|
-
/**
|
|
1101
|
-
* 当前使用请求时,输出请求的配置,一般用于DEBUG|DEV
|
|
1102
|
-
*/
|
|
1103
|
-
logDetails: false,
|
|
1104
|
-
};
|
|
1105
|
-
/**
|
|
1106
|
-
* 实例化
|
|
1107
|
-
* @param option 初始化配置
|
|
1108
|
-
*/
|
|
1109
|
-
constructor(option: Partial<HttpxInitOption> = {}) {
|
|
1110
|
-
if (typeof option.xmlHttpRequest !== "function") {
|
|
1111
|
-
console.warn(
|
|
1112
|
-
"[Httpx-constructor] 未传入GM_xmlhttpRequest函数或传入的GM_xmlhttpRequest不是Function,将默认使用window.fetch"
|
|
1113
|
-
);
|
|
1114
|
-
}
|
|
1115
|
-
CommonUtil.coverObjectFunctionThis(this);
|
|
1116
|
-
this.interceptors.request.context = this;
|
|
1117
|
-
this.interceptors.response.context = this;
|
|
1118
|
-
this.config(option);
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* 覆盖当前配置
|
|
1122
|
-
* @param option
|
|
1123
|
-
*/
|
|
1124
|
-
config(option: Partial<HttpxInitOption> = {}) {
|
|
1125
|
-
if (typeof option.xmlHttpRequest === "function") {
|
|
1126
|
-
this.GM_Api.xmlHttpRequest = option.xmlHttpRequest;
|
|
1127
|
-
}
|
|
1128
|
-
this.#defaultRequestOption = CommonUtil.assign(this.#defaultRequestOption, option);
|
|
1129
|
-
this.#defaultInitOption = CommonUtil.assign(this.#defaultInitOption, option);
|
|
1130
|
-
}
|
|
1131
|
-
/**
|
|
1132
|
-
* 拦截器
|
|
1133
|
-
*/
|
|
1134
|
-
interceptors = {
|
|
1135
|
-
/**
|
|
1136
|
-
* 请求拦截器
|
|
1137
|
-
*/
|
|
1138
|
-
request: {
|
|
1139
|
-
context: null as any as Httpx,
|
|
1140
|
-
/**
|
|
1141
|
-
* 添加拦截器
|
|
1142
|
-
* @param fn 设置的请求前回调函数,如果返回配置,则使用返回的配置,如果返回null|undefined,则阻止请求
|
|
1143
|
-
*/
|
|
1144
|
-
use(fn: <T extends Required<HttpxRequestOption>>(details: T) => void | T | Promise<void | T>) {
|
|
1145
|
-
if (typeof fn !== "function") {
|
|
1146
|
-
console.warn("[Httpx-interceptors-request] 请传入拦截器函数");
|
|
1147
|
-
return;
|
|
1148
|
-
}
|
|
1149
|
-
return this.context.HttpxRequestHook.add(fn);
|
|
1150
|
-
},
|
|
1151
|
-
/**
|
|
1152
|
-
* 移除拦截器
|
|
1153
|
-
* @param id 通过use返回的id
|
|
1154
|
-
*/
|
|
1155
|
-
eject(id: string) {
|
|
1156
|
-
return this.context.HttpxRequestHook.delete(id);
|
|
1157
|
-
},
|
|
1158
|
-
/**
|
|
1159
|
-
* 移除所有拦截器
|
|
1160
|
-
*/
|
|
1161
|
-
ejectAll() {
|
|
1162
|
-
this.context.HttpxRequestHook.clearAll();
|
|
1163
|
-
},
|
|
1164
|
-
},
|
|
1165
|
-
/**
|
|
1166
|
-
* 响应拦截器
|
|
1167
|
-
*/
|
|
1168
|
-
response: {
|
|
1169
|
-
context: null as any as Httpx,
|
|
1170
|
-
/**
|
|
1171
|
-
* 添加拦截器
|
|
1172
|
-
* @param successFn 设置的响应后回调函数,如果返回响应,则使用返回的响应,如果返回null|undefined,则阻止响应
|
|
1173
|
-
* + 2xx 范围内的状态码都会触发该函数
|
|
1174
|
-
* @param errorFn 设置的响应后回调函数,如果返回响应,则使用返回的响应,如果返回null|undefined,则阻止响应
|
|
1175
|
-
* + 超出 2xx 范围的状态码都会触发该函数
|
|
1176
|
-
*/
|
|
1177
|
-
use(
|
|
1178
|
-
successFn?: <T extends HttpxResponseData<HttpxRequestOption>>(
|
|
1179
|
-
response: T,
|
|
1180
|
-
details: HttpxRequestOption
|
|
1181
|
-
) => void | T,
|
|
1182
|
-
errorFn?: <T extends HttpxHookErrorData>(data: T) => void | T | Promise<void | T>
|
|
1183
|
-
) {
|
|
1184
|
-
if (typeof successFn !== "function" && typeof errorFn !== "function") {
|
|
1185
|
-
console.warn("[Httpx-interceptors-response] 必须传入一个拦截器函数");
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1188
|
-
return this.context.HttpxResponseHook.add(successFn!, errorFn!);
|
|
1189
|
-
},
|
|
1190
|
-
/**
|
|
1191
|
-
* 移除拦截器
|
|
1192
|
-
* @param id 通过use返回的id
|
|
1193
|
-
*/
|
|
1194
|
-
eject(id: string) {
|
|
1195
|
-
return this.context.HttpxResponseHook.delete(id);
|
|
1196
|
-
},
|
|
1197
|
-
/**
|
|
1198
|
-
* 移除所有拦截器
|
|
1199
|
-
*/
|
|
1200
|
-
ejectAll() {
|
|
1201
|
-
this.context.HttpxResponseHook.clearAll();
|
|
1202
|
-
},
|
|
1203
|
-
},
|
|
1204
|
-
};
|
|
1205
|
-
/**
|
|
1206
|
-
* 修改xmlHttpRequest
|
|
1207
|
-
* @param httpRequest 网络请求函数
|
|
1208
|
-
*/
|
|
1209
|
-
setXMLHttpRequest(httpRequest: (...args: any[]) => any) {
|
|
1210
|
-
this.GM_Api.xmlHttpRequest = httpRequest;
|
|
1211
|
-
}
|
|
1212
|
-
/**
|
|
1213
|
-
* GET 请求
|
|
1214
|
-
* @param details 配置
|
|
1215
|
-
*/
|
|
1216
|
-
get<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1217
|
-
/**
|
|
1218
|
-
* GET 请求
|
|
1219
|
-
* @param url 请求的url
|
|
1220
|
-
* @param details 配置
|
|
1221
|
-
*/
|
|
1222
|
-
get<T extends Omit<HttpxRequestOption, "url">>(
|
|
1223
|
-
url: string,
|
|
1224
|
-
details?: T
|
|
1225
|
-
): HttpxPromise<
|
|
1226
|
-
HttpxResponse<
|
|
1227
|
-
T & {
|
|
1228
|
-
/**
|
|
1229
|
-
* 请求的url
|
|
1230
|
-
*/
|
|
1231
|
-
url: string;
|
|
1232
|
-
}
|
|
1233
|
-
>
|
|
1234
|
-
>;
|
|
1235
|
-
/**
|
|
1236
|
-
* GET 请求
|
|
1237
|
-
* @param url 请求的url
|
|
1238
|
-
* @param details 配置
|
|
1239
|
-
*/
|
|
1240
|
-
get(...args: (string | HttpxRequestOption)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1241
|
-
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1242
|
-
useRequestOption.method = "GET";
|
|
1243
|
-
return this.request(useRequestOption, (option) => {
|
|
1244
|
-
Reflect.deleteProperty(option, "onprogress");
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
/**
|
|
1248
|
-
* POST 请求
|
|
1249
|
-
* @param details 配置
|
|
1250
|
-
*/
|
|
1251
|
-
post<T extends HttpxRequestOption>(details?: T): HttpxPromise<HttpxResponse<T>>;
|
|
1252
|
-
/**
|
|
1253
|
-
* POST 请求
|
|
1254
|
-
* @param url 请求的url
|
|
1255
|
-
* @param details 配置
|
|
1256
|
-
*/
|
|
1257
|
-
post<T extends Omit<HttpxRequestOption, "url">>(
|
|
1258
|
-
url: string,
|
|
1259
|
-
details?: T
|
|
1260
|
-
): HttpxPromise<
|
|
1261
|
-
HttpxResponse<
|
|
1262
|
-
T & {
|
|
1263
|
-
/**
|
|
1264
|
-
* 请求的url
|
|
1265
|
-
*/
|
|
1266
|
-
url: string;
|
|
1267
|
-
}
|
|
1268
|
-
>
|
|
1269
|
-
>;
|
|
1270
|
-
/**
|
|
1271
|
-
* POST 请求
|
|
1272
|
-
*/
|
|
1273
|
-
post(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1274
|
-
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1275
|
-
useRequestOption.method = "POST";
|
|
1276
|
-
return this.request(useRequestOption);
|
|
1277
|
-
}
|
|
1278
|
-
/**
|
|
1279
|
-
* HEAD 请求
|
|
1280
|
-
* @param details 配置
|
|
1281
|
-
*/
|
|
1282
|
-
head<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1283
|
-
/**
|
|
1284
|
-
* HEAD 请求
|
|
1285
|
-
* @param url 请求的url
|
|
1286
|
-
* @param details 配置
|
|
1287
|
-
*/
|
|
1288
|
-
head<T extends Omit<HttpxRequestOption, "url">>(
|
|
1289
|
-
url: string,
|
|
1290
|
-
details?: T
|
|
1291
|
-
): HttpxPromise<
|
|
1292
|
-
HttpxResponse<
|
|
1293
|
-
T & {
|
|
1294
|
-
/**
|
|
1295
|
-
* 请求的url
|
|
1296
|
-
*/
|
|
1297
|
-
url: string;
|
|
1298
|
-
}
|
|
1299
|
-
>
|
|
1300
|
-
>;
|
|
1301
|
-
/**
|
|
1302
|
-
* HEAD 请求
|
|
1303
|
-
*/
|
|
1304
|
-
head(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1305
|
-
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1306
|
-
useRequestOption.method = "HEAD";
|
|
1307
|
-
return this.request(useRequestOption, (option) => {
|
|
1308
|
-
Reflect.deleteProperty(option, "onprogress");
|
|
1309
|
-
});
|
|
1310
|
-
}
|
|
1311
|
-
/**
|
|
1312
|
-
* OPTIONS 请求
|
|
1313
|
-
* @param details 配置
|
|
1314
|
-
*/
|
|
1315
|
-
options<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1316
|
-
/**
|
|
1317
|
-
* OPTIONS 请求
|
|
1318
|
-
* @param url 请求的url
|
|
1319
|
-
* @param details 配置
|
|
1320
|
-
*/
|
|
1321
|
-
options<T extends Omit<HttpxRequestOption, "url">>(
|
|
1322
|
-
url: string,
|
|
1323
|
-
details?: T
|
|
1324
|
-
): HttpxPromise<
|
|
1325
|
-
HttpxResponse<
|
|
1326
|
-
T & {
|
|
1327
|
-
/**
|
|
1328
|
-
* 请求的url
|
|
1329
|
-
*/
|
|
1330
|
-
url: string;
|
|
1331
|
-
}
|
|
1332
|
-
>
|
|
1333
|
-
>;
|
|
1334
|
-
/**
|
|
1335
|
-
* OPTIONS 请求
|
|
1336
|
-
*/
|
|
1337
|
-
options(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1338
|
-
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1339
|
-
useRequestOption.method = "OPTIONS";
|
|
1340
|
-
return this.request(useRequestOption, (option) => {
|
|
1341
|
-
Reflect.deleteProperty(option, "onprogress");
|
|
1342
|
-
});
|
|
1343
|
-
}
|
|
1344
|
-
/**
|
|
1345
|
-
* DELETE 请求
|
|
1346
|
-
* @param details 配置
|
|
1347
|
-
*/
|
|
1348
|
-
delete<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1349
|
-
/**
|
|
1350
|
-
* DELETE 请求
|
|
1351
|
-
* @param url 请求的url
|
|
1352
|
-
* @param details 配置
|
|
1353
|
-
*/
|
|
1354
|
-
delete<T extends Omit<HttpxRequestOption, "url">>(
|
|
1355
|
-
url: string,
|
|
1356
|
-
details?: T
|
|
1357
|
-
): HttpxPromise<
|
|
1358
|
-
HttpxResponse<
|
|
1359
|
-
T & {
|
|
1360
|
-
/**
|
|
1361
|
-
* 请求的url
|
|
1362
|
-
*/
|
|
1363
|
-
url: string;
|
|
1364
|
-
}
|
|
1365
|
-
>
|
|
1366
|
-
>;
|
|
1367
|
-
/**
|
|
1368
|
-
* DELETE 请求
|
|
1369
|
-
*/
|
|
1370
|
-
delete(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1371
|
-
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1372
|
-
useRequestOption.method = "DELETE";
|
|
1373
|
-
return this.request(useRequestOption, (option) => {
|
|
1374
|
-
Reflect.deleteProperty(option, "onprogress");
|
|
1375
|
-
});
|
|
1376
|
-
}
|
|
1377
|
-
/**
|
|
1378
|
-
* PUT 请求
|
|
1379
|
-
* @param details 配置
|
|
1380
|
-
*/
|
|
1381
|
-
put<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1382
|
-
/**
|
|
1383
|
-
* PUT 请求
|
|
1384
|
-
* @param url 请求的url
|
|
1385
|
-
* @param details 配置
|
|
1386
|
-
*/
|
|
1387
|
-
put<T extends Omit<HttpxRequestOption, "url">>(
|
|
1388
|
-
url: string,
|
|
1389
|
-
details?: T
|
|
1390
|
-
): HttpxPromise<
|
|
1391
|
-
HttpxResponse<
|
|
1392
|
-
T & {
|
|
1393
|
-
/**
|
|
1394
|
-
* 请求的url
|
|
1395
|
-
*/
|
|
1396
|
-
url: string;
|
|
1397
|
-
}
|
|
1398
|
-
>
|
|
1399
|
-
>;
|
|
1400
|
-
/**
|
|
1401
|
-
* PUT 请求
|
|
1402
|
-
*/
|
|
1403
|
-
put(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1404
|
-
const userRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1405
|
-
userRequestOption.method = "PUT";
|
|
1406
|
-
return this.request(userRequestOption);
|
|
1407
|
-
}
|
|
1408
|
-
/**
|
|
1409
|
-
* 发送请求
|
|
1410
|
-
* @param details 配置
|
|
1411
|
-
* @param beforeRequestOption 处理请求前的配置
|
|
1412
|
-
*/
|
|
1413
|
-
request<T extends HttpxRequestOption>(
|
|
1414
|
-
details: T,
|
|
1415
|
-
beforeRequestOption?: (option: Required<T | HttpxRequestOption>) => void
|
|
1416
|
-
): HttpxPromise<HttpxResponse<T>> {
|
|
1417
|
-
// 对请求的参数进行合并处理
|
|
1418
|
-
const userRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(details);
|
|
1419
|
-
|
|
1420
|
-
/**
|
|
1421
|
-
* 取消请求
|
|
1422
|
-
*/
|
|
1423
|
-
let abortFn: ((...args: any[]) => any) | null = null;
|
|
1424
|
-
const promise = new globalThis.Promise<HttpxResponse<HttpxRequestOption>>(async (resolve, reject) => {
|
|
1425
|
-
// 请求配置
|
|
1426
|
-
let requestOption = this.HttpxRequestOption.getRequestOption(
|
|
1427
|
-
userRequestOption.method!,
|
|
1428
|
-
userRequestOption,
|
|
1429
|
-
(resultOption) => {
|
|
1430
|
-
resolve(resultOption);
|
|
1431
|
-
},
|
|
1432
|
-
(...args: any[]) => {
|
|
1433
|
-
reject(...args);
|
|
1434
|
-
}
|
|
1435
|
-
);
|
|
1436
|
-
requestOption = this.HttpxRequestOption.removeRequestNullOption(requestOption);
|
|
1437
|
-
if (typeof beforeRequestOption === "function") {
|
|
1438
|
-
beforeRequestOption(requestOption as Required<T>);
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
// 处理重试逻辑
|
|
1442
|
-
const requestResult = await this.HttpxRequest.request(requestOption);
|
|
1443
|
-
if (requestResult != null && typeof requestResult.abort === "function") {
|
|
1444
|
-
abortFn = () => {
|
|
1445
|
-
// 取消请求
|
|
1446
|
-
requestResult.abort();
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
}) as HttpxPromise<HttpxResponse<T>>;
|
|
1450
|
-
promise.abort = () => {
|
|
1451
|
-
if (typeof abortFn === "function") {
|
|
1452
|
-
abortFn();
|
|
1453
|
-
}
|
|
1454
|
-
};
|
|
1455
|
-
return promise;
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1
|
+
import { CommonUtil } from "./CommonUtil";
|
|
2
|
+
import { TryCatch } from "./TryCatch";
|
|
3
|
+
import type {
|
|
4
|
+
HttpxAllowInterceptConfig,
|
|
5
|
+
HttpxHookErrorData,
|
|
6
|
+
HttpxInitOption,
|
|
7
|
+
HttpxMethod,
|
|
8
|
+
HttpxPromise,
|
|
9
|
+
HttpxRequestOption,
|
|
10
|
+
HttpxResponse,
|
|
11
|
+
HttpxResponseData,
|
|
12
|
+
} from "./types/Httpx";
|
|
13
|
+
import { GenerateUUID } from "./UtilsCommon";
|
|
14
|
+
|
|
15
|
+
export class Httpx {
|
|
16
|
+
private GM_Api = {
|
|
17
|
+
xmlHttpRequest: null as ((...args: any[]) => any) | null,
|
|
18
|
+
};
|
|
19
|
+
private HttpxRequestHook = {
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
$config: {
|
|
24
|
+
configList: <
|
|
25
|
+
{
|
|
26
|
+
id: string;
|
|
27
|
+
fn: ((...args: any[]) => any) | Promise<(...args: any[]) => any>;
|
|
28
|
+
}[]
|
|
29
|
+
>[],
|
|
30
|
+
},
|
|
31
|
+
/**
|
|
32
|
+
* 发送请求前的回调
|
|
33
|
+
* 如果返回false则阻止本次返回
|
|
34
|
+
* @param details 当前的请求配置
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
async beforeRequestCallBack(details: HttpxRequestOption) {
|
|
38
|
+
if (typeof details.allowInterceptConfig === "boolean") {
|
|
39
|
+
if (!details.allowInterceptConfig) {
|
|
40
|
+
// 不允许拦截
|
|
41
|
+
return details;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
if (details.allowInterceptConfig != null) {
|
|
45
|
+
// 配置存在
|
|
46
|
+
// 细分处理是否拦截
|
|
47
|
+
if (
|
|
48
|
+
typeof details.allowInterceptConfig.beforeRequest === "boolean" &&
|
|
49
|
+
!details.allowInterceptConfig.beforeRequest
|
|
50
|
+
) {
|
|
51
|
+
// 设置了禁止拦截
|
|
52
|
+
return details;
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
// 配置不存在
|
|
56
|
+
// 默认允许拦截
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (let index = 0; index < this.$config.configList.length; index++) {
|
|
60
|
+
const item = this.$config.configList[index];
|
|
61
|
+
if (typeof item.fn === "function") {
|
|
62
|
+
const result = await item.fn(details);
|
|
63
|
+
if (result == null) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return details;
|
|
69
|
+
},
|
|
70
|
+
/**
|
|
71
|
+
* 添加请求前的回调处理配置
|
|
72
|
+
*/
|
|
73
|
+
add(fn: (...args: any[]) => any) {
|
|
74
|
+
if (typeof fn === "function") {
|
|
75
|
+
const uuid = GenerateUUID();
|
|
76
|
+
this.$config.configList.push({
|
|
77
|
+
id: uuid,
|
|
78
|
+
fn: fn,
|
|
79
|
+
});
|
|
80
|
+
return uuid;
|
|
81
|
+
} else {
|
|
82
|
+
console.warn("[Httpx-HttpxRequestHook.addBeforeRequestCallBack] fn is not a function");
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* 删除请求前的回调处理配置
|
|
87
|
+
* @param id
|
|
88
|
+
*/
|
|
89
|
+
delete(id: string) {
|
|
90
|
+
if (typeof id === "string") {
|
|
91
|
+
const findIndex = this.$config.configList.findIndex((item) => item.id === id);
|
|
92
|
+
if (findIndex !== -1) {
|
|
93
|
+
this.$config.configList.splice(findIndex, 1);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* 清空设置的请求前的回调处理配置
|
|
101
|
+
*/
|
|
102
|
+
clearAll() {
|
|
103
|
+
this.$config.configList = [];
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
private HttpxResponseHook = {
|
|
107
|
+
/**
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
$config: {
|
|
111
|
+
configList: <
|
|
112
|
+
{
|
|
113
|
+
id: string;
|
|
114
|
+
successFn?: (...args: any[]) => any | Promise<(...args: any[]) => any>;
|
|
115
|
+
errorFn?: (...args: any[]) => any | Promise<(...args: any[]) => any>;
|
|
116
|
+
}[]
|
|
117
|
+
>[],
|
|
118
|
+
},
|
|
119
|
+
/**
|
|
120
|
+
* 成功的回调
|
|
121
|
+
* @param response 响应
|
|
122
|
+
* @param details 请求的配置
|
|
123
|
+
*/
|
|
124
|
+
async successResponseCallBack(response: HttpxResponseData<HttpxRequestOption>, details: HttpxRequestOption) {
|
|
125
|
+
if (typeof details.allowInterceptConfig === "boolean") {
|
|
126
|
+
if (!details.allowInterceptConfig) {
|
|
127
|
+
// 不允许拦截
|
|
128
|
+
return details;
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
if (details.allowInterceptConfig != null) {
|
|
132
|
+
// 配置存在
|
|
133
|
+
// 细分处理是否拦截
|
|
134
|
+
if (
|
|
135
|
+
typeof details.allowInterceptConfig.afterResponseSuccess === "boolean" &&
|
|
136
|
+
!details.allowInterceptConfig.afterResponseSuccess
|
|
137
|
+
) {
|
|
138
|
+
// 设置了禁止拦截
|
|
139
|
+
return details;
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
// 配置不存在
|
|
143
|
+
// 默认允许拦截
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
for (let index = 0; index < this.$config.configList.length; index++) {
|
|
147
|
+
const item = this.$config.configList[index];
|
|
148
|
+
if (typeof item.successFn === "function") {
|
|
149
|
+
const result = await item.successFn(response, details);
|
|
150
|
+
if (result == null) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return response;
|
|
156
|
+
},
|
|
157
|
+
/**
|
|
158
|
+
* 失败的回调
|
|
159
|
+
* @param data 配置
|
|
160
|
+
* @returns
|
|
161
|
+
* 返回null|undefined就是拦截掉了
|
|
162
|
+
*/
|
|
163
|
+
async errorResponseCallBack<T extends HttpxHookErrorData>(data: T) {
|
|
164
|
+
if (typeof data.details.allowInterceptConfig === "boolean") {
|
|
165
|
+
if (!data.details.allowInterceptConfig) {
|
|
166
|
+
// 不允许拦截
|
|
167
|
+
return data;
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
if (data.details.allowInterceptConfig != null) {
|
|
171
|
+
// 配置存在
|
|
172
|
+
// 细分处理是否拦截
|
|
173
|
+
if (
|
|
174
|
+
typeof data.details.allowInterceptConfig.afterResponseError === "boolean" &&
|
|
175
|
+
!data.details.allowInterceptConfig.afterResponseError
|
|
176
|
+
) {
|
|
177
|
+
// 设置了禁止拦截
|
|
178
|
+
return data;
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
// 配置不存在
|
|
182
|
+
// 默认允许拦截
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
for (let index = 0; index < this.$config.configList.length; index++) {
|
|
186
|
+
const item = this.$config.configList[index];
|
|
187
|
+
if (typeof item.errorFn === "function") {
|
|
188
|
+
const result = await item.errorFn(data);
|
|
189
|
+
if (result == null) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return data;
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* 添加请求前的回调处理配置
|
|
198
|
+
*/
|
|
199
|
+
add(successFn?: (...args: any[]) => any, errorFn?: (...args: any[]) => any) {
|
|
200
|
+
const id = GenerateUUID();
|
|
201
|
+
this.$config.configList.push({
|
|
202
|
+
id: id,
|
|
203
|
+
successFn: successFn,
|
|
204
|
+
errorFn: errorFn,
|
|
205
|
+
});
|
|
206
|
+
return id;
|
|
207
|
+
},
|
|
208
|
+
/**
|
|
209
|
+
* 删除请求前的回调处理配置
|
|
210
|
+
* @param id
|
|
211
|
+
*/
|
|
212
|
+
delete(id: string) {
|
|
213
|
+
if (typeof id === "string") {
|
|
214
|
+
const findIndex = this.$config.configList.findIndex((item) => item.id === id);
|
|
215
|
+
if (findIndex !== -1) {
|
|
216
|
+
this.$config.configList.splice(findIndex, 1);
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
* 清空设置的请求前的回调处理配置
|
|
224
|
+
*/
|
|
225
|
+
clearAll() {
|
|
226
|
+
this.$config.configList = [];
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
private HttpxRequestOption = {
|
|
230
|
+
context: this,
|
|
231
|
+
/**
|
|
232
|
+
* 对请求的参数进行合并处理
|
|
233
|
+
*/
|
|
234
|
+
handleBeforeRequestOptionArgs(...args: (HttpxRequestOption | string)[]) {
|
|
235
|
+
const option: HttpxRequestOption = {
|
|
236
|
+
url: void 0 as any as string,
|
|
237
|
+
};
|
|
238
|
+
if (typeof args[0] === "string") {
|
|
239
|
+
/* 传入的是url,转为配置 */
|
|
240
|
+
const url = args[0];
|
|
241
|
+
option.url = url;
|
|
242
|
+
if (typeof args[1] === "object") {
|
|
243
|
+
/* 处理第二个参数details */
|
|
244
|
+
const optionArg = args[1];
|
|
245
|
+
CommonUtil.assign(option, optionArg, true);
|
|
246
|
+
option.url = url;
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
/* 传入的是配置 */
|
|
250
|
+
const optionArg = args[0];
|
|
251
|
+
CommonUtil.assign(option, optionArg, true);
|
|
252
|
+
}
|
|
253
|
+
return option;
|
|
254
|
+
},
|
|
255
|
+
/**
|
|
256
|
+
* 获取请求配置
|
|
257
|
+
* @param method 当前请求方法,默认get
|
|
258
|
+
* @param userRequestOption 用户的请求配置
|
|
259
|
+
* @param resolve promise回调
|
|
260
|
+
* @param reject promise抛出错误回调
|
|
261
|
+
*/
|
|
262
|
+
getRequestOption(
|
|
263
|
+
method: HttpxMethod,
|
|
264
|
+
userRequestOption: HttpxRequestOption,
|
|
265
|
+
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
266
|
+
reject: (...args: any[]) => void
|
|
267
|
+
) {
|
|
268
|
+
const that = this;
|
|
269
|
+
let url = userRequestOption.url || this.context.#defaultRequestOption.url;
|
|
270
|
+
if (typeof url === "string") {
|
|
271
|
+
// 去除左右空格
|
|
272
|
+
url = url.trim();
|
|
273
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
274
|
+
// 标准的http请求
|
|
275
|
+
} else {
|
|
276
|
+
if (typeof this.context.#defaultInitOption.baseURL === "string") {
|
|
277
|
+
// 设置了基础域
|
|
278
|
+
url = this.context.#defaultInitOption.baseURL + url;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const requestOption = <Required<HttpxRequestOption>>{
|
|
283
|
+
url: url,
|
|
284
|
+
method: (method || "GET").toString().toUpperCase().trim(),
|
|
285
|
+
timeout: userRequestOption.timeout || this.context.#defaultRequestOption.timeout,
|
|
286
|
+
responseType: userRequestOption.responseType || this.context.#defaultRequestOption.responseType,
|
|
287
|
+
/* 对象使用深拷贝 */
|
|
288
|
+
headers: CommonUtil.deepClone(this.context.#defaultRequestOption.headers),
|
|
289
|
+
data: userRequestOption.data || this.context.#defaultRequestOption.data,
|
|
290
|
+
redirect: userRequestOption.redirect || this.context.#defaultRequestOption.redirect,
|
|
291
|
+
cookie: userRequestOption.cookie || this.context.#defaultRequestOption.cookie,
|
|
292
|
+
cookiePartition: userRequestOption.cookiePartition || this.context.#defaultRequestOption.cookiePartition,
|
|
293
|
+
binary: userRequestOption.binary || this.context.#defaultRequestOption.binary,
|
|
294
|
+
nocache: userRequestOption.nocache || this.context.#defaultRequestOption.nocache,
|
|
295
|
+
revalidate: userRequestOption.revalidate || this.context.#defaultRequestOption.revalidate,
|
|
296
|
+
/* 对象使用深拷贝 */
|
|
297
|
+
context: CommonUtil.deepClone(userRequestOption.context || this.context.#defaultRequestOption.context),
|
|
298
|
+
overrideMimeType: userRequestOption.overrideMimeType || this.context.#defaultRequestOption.overrideMimeType,
|
|
299
|
+
anonymous: userRequestOption.anonymous || this.context.#defaultRequestOption.anonymous,
|
|
300
|
+
fetch: userRequestOption.fetch || this.context.#defaultRequestOption.fetch,
|
|
301
|
+
/* 对象使用深拷贝 */
|
|
302
|
+
fetchInit: CommonUtil.deepClone(this.context.#defaultRequestOption.fetchInit),
|
|
303
|
+
allowInterceptConfig: {
|
|
304
|
+
beforeRequest: (this.context.#defaultRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig)
|
|
305
|
+
.beforeRequest,
|
|
306
|
+
afterResponseSuccess: (this.context.#defaultRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig)
|
|
307
|
+
.afterResponseSuccess,
|
|
308
|
+
afterResponseError: (this.context.#defaultRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig)
|
|
309
|
+
.afterResponseError,
|
|
310
|
+
},
|
|
311
|
+
user: userRequestOption.user || this.context.#defaultRequestOption.user,
|
|
312
|
+
password: userRequestOption.password || this.context.#defaultRequestOption.password,
|
|
313
|
+
onabort(...args) {
|
|
314
|
+
that.context.HttpxResponseCallBack.onAbort(
|
|
315
|
+
userRequestOption as Required<HttpxRequestOption>,
|
|
316
|
+
resolve,
|
|
317
|
+
reject,
|
|
318
|
+
args
|
|
319
|
+
);
|
|
320
|
+
},
|
|
321
|
+
onerror(...args) {
|
|
322
|
+
that.context.HttpxResponseCallBack.onError(
|
|
323
|
+
userRequestOption as Required<HttpxRequestOption>,
|
|
324
|
+
resolve,
|
|
325
|
+
reject,
|
|
326
|
+
args
|
|
327
|
+
);
|
|
328
|
+
},
|
|
329
|
+
onloadstart(...args) {
|
|
330
|
+
that.context.HttpxResponseCallBack.onLoadStart(userRequestOption as Required<HttpxRequestOption>, args);
|
|
331
|
+
},
|
|
332
|
+
onprogress(...args) {
|
|
333
|
+
that.context.HttpxResponseCallBack.onProgress(userRequestOption as Required<HttpxRequestOption>, args);
|
|
334
|
+
},
|
|
335
|
+
onreadystatechange(...args) {
|
|
336
|
+
that.context.HttpxResponseCallBack.onReadyStateChange(
|
|
337
|
+
userRequestOption as Required<HttpxRequestOption>,
|
|
338
|
+
args
|
|
339
|
+
);
|
|
340
|
+
},
|
|
341
|
+
ontimeout(...args) {
|
|
342
|
+
that.context.HttpxResponseCallBack.onTimeout(
|
|
343
|
+
userRequestOption as Required<HttpxRequestOption>,
|
|
344
|
+
resolve,
|
|
345
|
+
reject,
|
|
346
|
+
args
|
|
347
|
+
);
|
|
348
|
+
},
|
|
349
|
+
onload(...args) {
|
|
350
|
+
that.context.HttpxResponseCallBack.onLoad(
|
|
351
|
+
userRequestOption as Required<HttpxRequestOption>,
|
|
352
|
+
resolve,
|
|
353
|
+
reject,
|
|
354
|
+
args
|
|
355
|
+
);
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
// 补全allowInterceptConfig参数
|
|
359
|
+
if (typeof userRequestOption.allowInterceptConfig === "boolean") {
|
|
360
|
+
const allowInterceptConfigKeys = Object.keys(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig);
|
|
361
|
+
allowInterceptConfigKeys.forEach((keyName) => {
|
|
362
|
+
Reflect.set(
|
|
363
|
+
requestOption.allowInterceptConfig as HttpxAllowInterceptConfig,
|
|
364
|
+
keyName,
|
|
365
|
+
userRequestOption.allowInterceptConfig
|
|
366
|
+
);
|
|
367
|
+
});
|
|
368
|
+
} else {
|
|
369
|
+
if (
|
|
370
|
+
typeof userRequestOption.allowInterceptConfig === "object" &&
|
|
371
|
+
userRequestOption.allowInterceptConfig != null
|
|
372
|
+
) {
|
|
373
|
+
const allowInterceptConfigKeys = Object.keys(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig);
|
|
374
|
+
allowInterceptConfigKeys.forEach((keyName) => {
|
|
375
|
+
const value = Reflect.get(
|
|
376
|
+
userRequestOption.allowInterceptConfig as HttpxAllowInterceptConfig,
|
|
377
|
+
keyName
|
|
378
|
+
) as boolean;
|
|
379
|
+
if (
|
|
380
|
+
typeof value === "boolean" &&
|
|
381
|
+
Reflect.has(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig, keyName)
|
|
382
|
+
) {
|
|
383
|
+
Reflect.set(requestOption.allowInterceptConfig as HttpxAllowInterceptConfig, keyName, value);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (typeof this.context.GM_Api.xmlHttpRequest !== "function") {
|
|
389
|
+
// GM函数不存在,强制使用fetch
|
|
390
|
+
requestOption.fetch = true;
|
|
391
|
+
}
|
|
392
|
+
if (typeof requestOption.headers === "object") {
|
|
393
|
+
if (typeof userRequestOption.headers === "object") {
|
|
394
|
+
const headerKeys = Object.keys(requestOption.headers);
|
|
395
|
+
headerKeys.forEach((keyName) => {
|
|
396
|
+
if (keyName in requestOption.headers && userRequestOption!.headers?.[keyName] == null) {
|
|
397
|
+
/* 在默认的header中存在,且设置它新的值为空,那么就是默认的值 */
|
|
398
|
+
Reflect.deleteProperty(requestOption.headers, keyName);
|
|
399
|
+
} else {
|
|
400
|
+
requestOption.headers[keyName] = userRequestOption?.headers?.[keyName];
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
} else {
|
|
404
|
+
/* details.headers为空 */
|
|
405
|
+
/* 不做处理 */
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
/* 默认的headers不是对象,那么就直接使用新的 */
|
|
409
|
+
Reflect.set(requestOption, "headers", userRequestOption.headers);
|
|
410
|
+
}
|
|
411
|
+
if (typeof requestOption.fetchInit === "object") {
|
|
412
|
+
/* 使用assign替换且添加 */
|
|
413
|
+
if (typeof userRequestOption.fetchInit === "object") {
|
|
414
|
+
const fetchInitKeys = Object.keys(requestOption.fetchInit);
|
|
415
|
+
fetchInitKeys.forEach((keyName) => {
|
|
416
|
+
if (keyName in requestOption.fetchInit && Reflect.get(userRequestOption.fetchInit ?? {}, keyName) == null) {
|
|
417
|
+
/* 在默认的fetchInit中存在,且设置它新的值为空,那么就是默认的值 */
|
|
418
|
+
Reflect.deleteProperty(requestOption.fetchInit, keyName);
|
|
419
|
+
} else {
|
|
420
|
+
Reflect.set(requestOption.fetchInit, keyName, Reflect.get(userRequestOption.fetchInit!, keyName));
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
Reflect.set(requestOption, "fetchInit", userRequestOption.fetchInit);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 处理新的cookiePartition
|
|
429
|
+
if (typeof requestOption.cookiePartition === "object" && requestOption.cookiePartition != null) {
|
|
430
|
+
if (
|
|
431
|
+
Reflect.has(requestOption.cookiePartition, "topLevelSite") &&
|
|
432
|
+
typeof requestOption.cookiePartition.topLevelSite !== "string"
|
|
433
|
+
) {
|
|
434
|
+
// topLevelSite必须是字符串
|
|
435
|
+
Reflect.deleteProperty(requestOption.cookiePartition, "topLevelSite");
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/* 完善请求的url */
|
|
440
|
+
try {
|
|
441
|
+
new URL(requestOption.url);
|
|
442
|
+
} catch {
|
|
443
|
+
if (requestOption.url.startsWith("//")) {
|
|
444
|
+
// 补充https:
|
|
445
|
+
requestOption.url = globalThis.location.protocol + requestOption.url;
|
|
446
|
+
} else if (requestOption.url.startsWith("/")) {
|
|
447
|
+
// 补充origin
|
|
448
|
+
requestOption.url = globalThis.location.origin + requestOption.url;
|
|
449
|
+
} else {
|
|
450
|
+
// 补充origin+/
|
|
451
|
+
requestOption.url = `${globalThis.location.origin}/${requestOption.url}`;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (requestOption.fetchInit && !requestOption.fetch) {
|
|
456
|
+
// 清空fetchInit
|
|
457
|
+
Reflect.deleteProperty(requestOption, "fetchInit");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// 转换data类型
|
|
461
|
+
try {
|
|
462
|
+
/** 是否对数据进行处理 */
|
|
463
|
+
const processData = userRequestOption.processData ?? true;
|
|
464
|
+
if (requestOption.data != null && processData) {
|
|
465
|
+
const method = requestOption.method;
|
|
466
|
+
if (method === "GET" || method === "HEAD") {
|
|
467
|
+
// GET类型,data如果有,那么需要转为searchParams
|
|
468
|
+
const urlObj = new URL(requestOption.url);
|
|
469
|
+
let urlSearch = "";
|
|
470
|
+
let isHandler = false;
|
|
471
|
+
if (typeof requestOption.data === "string") {
|
|
472
|
+
isHandler = true;
|
|
473
|
+
urlSearch = requestOption.data;
|
|
474
|
+
} else if (typeof requestOption.data === "object") {
|
|
475
|
+
isHandler = true;
|
|
476
|
+
// URLSearchParams参数可以转普通的string:string,包括FormData
|
|
477
|
+
const searchParams = new URLSearchParams(requestOption.data as Record<string, string>);
|
|
478
|
+
urlSearch = searchParams.toString();
|
|
479
|
+
}
|
|
480
|
+
if (isHandler) {
|
|
481
|
+
// GET/HEAD请求不支持data参数
|
|
482
|
+
// 对data进行处理了才可以删除
|
|
483
|
+
Reflect.deleteProperty(requestOption, "data");
|
|
484
|
+
}
|
|
485
|
+
if (urlSearch != "") {
|
|
486
|
+
if (urlObj.search === "") {
|
|
487
|
+
// url没有search参数,直接覆盖
|
|
488
|
+
urlObj.search = urlSearch;
|
|
489
|
+
} else {
|
|
490
|
+
// 有search参数
|
|
491
|
+
if (urlObj.search.endsWith("&")) {
|
|
492
|
+
// xxx=xxx&
|
|
493
|
+
urlObj.search = urlObj.search + urlSearch;
|
|
494
|
+
} else {
|
|
495
|
+
// xxx=xxx&xxx=
|
|
496
|
+
urlObj.search = `${urlObj.search}&${urlSearch}`;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
requestOption.url = urlObj.toString();
|
|
501
|
+
} else if (method === "POST" && requestOption.headers != null) {
|
|
502
|
+
// POST类型,data如果是FormData,那么需要转为string
|
|
503
|
+
const headersKeyList = Object.keys(requestOption.headers);
|
|
504
|
+
const ContentTypeIndex = headersKeyList.findIndex((headerKey) => {
|
|
505
|
+
return (
|
|
506
|
+
headerKey.trim().toLowerCase() === "content-type" &&
|
|
507
|
+
typeof requestOption.headers[headerKey] === "string"
|
|
508
|
+
);
|
|
509
|
+
});
|
|
510
|
+
if (ContentTypeIndex !== -1) {
|
|
511
|
+
const ContentTypeKey = headersKeyList[ContentTypeIndex];
|
|
512
|
+
const ContentType = requestOption.headers[ContentTypeKey] as string;
|
|
513
|
+
// 设置了Content-Type
|
|
514
|
+
if (ContentType.includes("application/json")) {
|
|
515
|
+
// application/json
|
|
516
|
+
if (requestOption.data instanceof FormData) {
|
|
517
|
+
const entries: { [key: string]: any } = {};
|
|
518
|
+
requestOption.data.forEach((value, key) => {
|
|
519
|
+
entries[key] = value;
|
|
520
|
+
});
|
|
521
|
+
requestOption.data = JSON.stringify(entries);
|
|
522
|
+
} else if (typeof requestOption.data === "object") {
|
|
523
|
+
requestOption.data = JSON.stringify(requestOption.data);
|
|
524
|
+
}
|
|
525
|
+
} else if (ContentType.includes("application/x-www-form-urlencoded")) {
|
|
526
|
+
// application/x-www-form-urlencoded
|
|
527
|
+
if (typeof requestOption.data === "object") {
|
|
528
|
+
requestOption.data = new URLSearchParams(requestOption.data as Record<string, string>).toString();
|
|
529
|
+
}
|
|
530
|
+
} else if (ContentType.includes("multipart/form-data")) {
|
|
531
|
+
// multipart/form-data
|
|
532
|
+
if (requestOption.data instanceof FormData) {
|
|
533
|
+
Reflect.deleteProperty(requestOption.headers, ContentTypeKey);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
} catch (error) {
|
|
540
|
+
console.warn("Httpx ==> 转换data参数错误", error);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return requestOption;
|
|
544
|
+
},
|
|
545
|
+
/**
|
|
546
|
+
* 处理发送请求的配置,去除值为undefined、空function的值
|
|
547
|
+
* @param option 请求配置
|
|
548
|
+
*/
|
|
549
|
+
removeRequestNullOption(option: Required<HttpxRequestOption>): Required<HttpxRequestOption> {
|
|
550
|
+
const optionKeys = Object.keys(option);
|
|
551
|
+
optionKeys.forEach((keyName) => {
|
|
552
|
+
const optionValue = option[keyName as keyof HttpxRequestOption];
|
|
553
|
+
if (optionValue == null || (optionValue instanceof Function && CommonUtil.isNull(optionValue))) {
|
|
554
|
+
Reflect.deleteProperty(option, keyName);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
if (CommonUtil.isNull(option.url)) {
|
|
559
|
+
throw new TypeError(`Utils.Httpx 参数url不能为空:${option.url}`);
|
|
560
|
+
}
|
|
561
|
+
return option;
|
|
562
|
+
},
|
|
563
|
+
/**
|
|
564
|
+
* 处理fetch的配置
|
|
565
|
+
* @param option 请求配置
|
|
566
|
+
*/
|
|
567
|
+
handleFetchOption(option: Required<HttpxRequestOption>) {
|
|
568
|
+
/**
|
|
569
|
+
* fetch的请求配置
|
|
570
|
+
**/
|
|
571
|
+
const fetchRequestOption = <RequestInit>{};
|
|
572
|
+
if ((option.method === "GET" || option.method === "HEAD") && option.data != null) {
|
|
573
|
+
/* GET 或 HEAD 方法的请求不能包含 body 信息 */
|
|
574
|
+
Reflect.deleteProperty(option, "data");
|
|
575
|
+
}
|
|
576
|
+
/* 中止信号控制器 */
|
|
577
|
+
const abortController = new AbortController();
|
|
578
|
+
const signal = abortController.signal;
|
|
579
|
+
signal.onabort = () => {
|
|
580
|
+
option.onabort({
|
|
581
|
+
isFetch: true,
|
|
582
|
+
responseText: "",
|
|
583
|
+
response: null,
|
|
584
|
+
readyState: 4,
|
|
585
|
+
responseHeaders: "",
|
|
586
|
+
status: 0,
|
|
587
|
+
statusText: "",
|
|
588
|
+
error: "aborted",
|
|
589
|
+
});
|
|
590
|
+
};
|
|
591
|
+
// 设置请求
|
|
592
|
+
fetchRequestOption.method = option.method ?? "GET";
|
|
593
|
+
// 设置请求头
|
|
594
|
+
fetchRequestOption.headers = option.headers;
|
|
595
|
+
// 设置请求体
|
|
596
|
+
fetchRequestOption.body = option.data as string | FormData;
|
|
597
|
+
// 设置跨域
|
|
598
|
+
fetchRequestOption.mode = "cors";
|
|
599
|
+
// 设置包含
|
|
600
|
+
fetchRequestOption.credentials = "include";
|
|
601
|
+
// 设置不缓存
|
|
602
|
+
fetchRequestOption.cache = "no-cache";
|
|
603
|
+
// 设置始终重定向
|
|
604
|
+
fetchRequestOption.redirect = "follow";
|
|
605
|
+
// 设置referer跨域
|
|
606
|
+
fetchRequestOption.referrerPolicy = "origin-when-cross-origin";
|
|
607
|
+
// 设置信号中断
|
|
608
|
+
fetchRequestOption.signal = signal;
|
|
609
|
+
Object.assign(fetchRequestOption, option.fetchInit || {});
|
|
610
|
+
return {
|
|
611
|
+
fetchOption: option,
|
|
612
|
+
fetchRequestOption: fetchRequestOption,
|
|
613
|
+
abortController: abortController,
|
|
614
|
+
};
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
private HttpxResponseCallBack = {
|
|
618
|
+
context: this,
|
|
619
|
+
/**
|
|
620
|
+
* onabort请求被取消-触发
|
|
621
|
+
* @param details 配置
|
|
622
|
+
* @param resolve promise回调
|
|
623
|
+
* @param _reject promise抛出错误回调
|
|
624
|
+
* @param argsResult 返回的参数列表
|
|
625
|
+
*/
|
|
626
|
+
async onAbort(
|
|
627
|
+
details: Required<HttpxRequestOption>,
|
|
628
|
+
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
629
|
+
_reject: (...args: any[]) => void,
|
|
630
|
+
argsResult: any
|
|
631
|
+
) {
|
|
632
|
+
// console.log(argsResult);
|
|
633
|
+
if (typeof details?.onabort === "function") {
|
|
634
|
+
details.onabort.apply(this, argsResult);
|
|
635
|
+
} else if (typeof this.context.#defaultRequestOption?.onabort === "function") {
|
|
636
|
+
this.context.#defaultRequestOption.onabort.apply(this, argsResult);
|
|
637
|
+
}
|
|
638
|
+
let response = argsResult;
|
|
639
|
+
if (response.length) {
|
|
640
|
+
response = response[0];
|
|
641
|
+
}
|
|
642
|
+
if (
|
|
643
|
+
(await this.context.HttpxResponseHook.errorResponseCallBack({
|
|
644
|
+
type: "onabort",
|
|
645
|
+
error: new Error("request canceled"),
|
|
646
|
+
response: null,
|
|
647
|
+
details: details,
|
|
648
|
+
})) == null
|
|
649
|
+
) {
|
|
650
|
+
// reject(new Error("response is intercept with onabort"));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
resolve({
|
|
654
|
+
data: response,
|
|
655
|
+
details: details,
|
|
656
|
+
msg: "请求被取消",
|
|
657
|
+
status: false,
|
|
658
|
+
statusCode: -1,
|
|
659
|
+
type: "onabort",
|
|
660
|
+
});
|
|
661
|
+
},
|
|
662
|
+
/**
|
|
663
|
+
* ontimeout请求超时-触发
|
|
664
|
+
* @param details 配置
|
|
665
|
+
* @param resolve 回调
|
|
666
|
+
* @param reject 抛出错误
|
|
667
|
+
* @param argsResult 返回的参数列表
|
|
668
|
+
*/
|
|
669
|
+
async onTimeout(
|
|
670
|
+
details: Required<HttpxRequestOption>,
|
|
671
|
+
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
672
|
+
_reject: (...args: any[]) => void,
|
|
673
|
+
argsResult: any
|
|
674
|
+
) {
|
|
675
|
+
// console.log(argsResult);
|
|
676
|
+
if (typeof details?.ontimeout === "function") {
|
|
677
|
+
// 执行配置中的ontime回调
|
|
678
|
+
details.ontimeout.apply(this, argsResult);
|
|
679
|
+
} else if (typeof this.context.#defaultRequestOption?.ontimeout === "function") {
|
|
680
|
+
// 执行默认配置的ontime回调
|
|
681
|
+
this.context.#defaultRequestOption.ontimeout.apply(this, argsResult);
|
|
682
|
+
}
|
|
683
|
+
// 获取响应结果
|
|
684
|
+
let response = argsResult;
|
|
685
|
+
if (response.length) {
|
|
686
|
+
response = response[0];
|
|
687
|
+
}
|
|
688
|
+
// 执行错误回调的钩子
|
|
689
|
+
if (
|
|
690
|
+
(await this.context.HttpxResponseHook.errorResponseCallBack({
|
|
691
|
+
type: "ontimeout",
|
|
692
|
+
error: new Error("request timeout"),
|
|
693
|
+
response: response,
|
|
694
|
+
details: details,
|
|
695
|
+
})) == null
|
|
696
|
+
) {
|
|
697
|
+
// reject(new Error("response is intercept with ontimeout"));
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
resolve({
|
|
701
|
+
data: response,
|
|
702
|
+
details: details,
|
|
703
|
+
msg: "请求超时",
|
|
704
|
+
status: false,
|
|
705
|
+
statusCode: 0,
|
|
706
|
+
type: "ontimeout",
|
|
707
|
+
});
|
|
708
|
+
},
|
|
709
|
+
/**
|
|
710
|
+
* onerror请求异常-触发
|
|
711
|
+
* @param details 配置
|
|
712
|
+
* @param resolve 回调
|
|
713
|
+
* @param _reject 抛出错误
|
|
714
|
+
* @param argsResult 返回的参数列表
|
|
715
|
+
*/
|
|
716
|
+
async onError(
|
|
717
|
+
details: Required<HttpxRequestOption>,
|
|
718
|
+
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
719
|
+
_reject: (...args: any[]) => void,
|
|
720
|
+
argsResult: any
|
|
721
|
+
) {
|
|
722
|
+
// console.log(argsResult);
|
|
723
|
+
if (typeof details?.onerror === "function") {
|
|
724
|
+
details.onerror.apply(this, argsResult);
|
|
725
|
+
} else if (typeof this.context.#defaultRequestOption?.onerror === "function") {
|
|
726
|
+
this.context.#defaultRequestOption.onerror.apply(this, argsResult);
|
|
727
|
+
}
|
|
728
|
+
let response = argsResult;
|
|
729
|
+
if (response.length) {
|
|
730
|
+
response = response[0];
|
|
731
|
+
}
|
|
732
|
+
if (
|
|
733
|
+
(await this.context.HttpxResponseHook.errorResponseCallBack({
|
|
734
|
+
type: "onerror",
|
|
735
|
+
error: new Error("request error"),
|
|
736
|
+
response: response,
|
|
737
|
+
details: details,
|
|
738
|
+
})) == null
|
|
739
|
+
) {
|
|
740
|
+
// reject(new Error("response is intercept with onerror"));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
resolve({
|
|
744
|
+
data: response,
|
|
745
|
+
details: details,
|
|
746
|
+
msg: "请求异常",
|
|
747
|
+
status: false,
|
|
748
|
+
statusCode: response["status"],
|
|
749
|
+
type: "onerror",
|
|
750
|
+
});
|
|
751
|
+
},
|
|
752
|
+
/**
|
|
753
|
+
* onload加载完毕-触发
|
|
754
|
+
* @param details 请求的配置
|
|
755
|
+
* @param resolve 回调
|
|
756
|
+
* @param _reject 抛出错误
|
|
757
|
+
* @param argsResult 返回的参数列表
|
|
758
|
+
*/
|
|
759
|
+
async onLoad(
|
|
760
|
+
details: Required<HttpxRequestOption>,
|
|
761
|
+
resolve: (resultOption: HttpxResponse<HttpxRequestOption>) => void,
|
|
762
|
+
_reject: (...args: any[]) => void,
|
|
763
|
+
argsResult: any[]
|
|
764
|
+
) {
|
|
765
|
+
// console.log(argsResult);
|
|
766
|
+
/* X浏览器会因为设置了responseType导致不返回responseText */
|
|
767
|
+
const originResponse: HttpxResponseData<HttpxRequestOption> = argsResult[0];
|
|
768
|
+
/* responseText为空,response不为空的情况 */
|
|
769
|
+
if (CommonUtil.isNull(originResponse["responseText"]) && CommonUtil.isNotNull(originResponse["response"])) {
|
|
770
|
+
if (typeof originResponse["response"] === "object") {
|
|
771
|
+
TryCatch().run(() => {
|
|
772
|
+
originResponse["responseText"] = JSON.stringify(originResponse["response"]);
|
|
773
|
+
});
|
|
774
|
+
} else {
|
|
775
|
+
originResponse["responseText"] = originResponse["response"] as string;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/* response为空,responseText不为空的情况 */
|
|
780
|
+
if (
|
|
781
|
+
originResponse["response"] == null &&
|
|
782
|
+
typeof originResponse["responseText"] === "string" &&
|
|
783
|
+
originResponse["responseText"].trim() !== ""
|
|
784
|
+
) {
|
|
785
|
+
/** 原始的请求text */
|
|
786
|
+
const httpxResponseText = originResponse.responseText;
|
|
787
|
+
// 自定义个新的response
|
|
788
|
+
let httpxResponse: any = httpxResponseText;
|
|
789
|
+
if (details.responseType === "json") {
|
|
790
|
+
httpxResponse = CommonUtil.toJSON(httpxResponseText);
|
|
791
|
+
} else if (details.responseType === "document") {
|
|
792
|
+
const parser = new DOMParser();
|
|
793
|
+
httpxResponse = parser.parseFromString(httpxResponseText, "text/html");
|
|
794
|
+
} else if (details.responseType === "arraybuffer") {
|
|
795
|
+
const encoder = new TextEncoder();
|
|
796
|
+
const arrayBuffer = encoder.encode(httpxResponseText);
|
|
797
|
+
httpxResponse = arrayBuffer;
|
|
798
|
+
} else if (details.responseType === "blob") {
|
|
799
|
+
const encoder = new TextEncoder();
|
|
800
|
+
const arrayBuffer = encoder.encode(httpxResponseText);
|
|
801
|
+
httpxResponse = new Blob([arrayBuffer]);
|
|
802
|
+
}
|
|
803
|
+
// 尝试覆盖原response
|
|
804
|
+
try {
|
|
805
|
+
const setStatus = Reflect.set(originResponse, "response", httpxResponse);
|
|
806
|
+
if (!setStatus) {
|
|
807
|
+
console.warn("[Httpx-HttpxCallBack.oonLoad] 覆盖原始 response 失败,尝试添加新的httpxResponse");
|
|
808
|
+
try {
|
|
809
|
+
Reflect.set(originResponse, "httpxResponse", httpxResponse);
|
|
810
|
+
} catch {
|
|
811
|
+
console.warn("[Httpx-HttpxCallBack.oonLoad] httpxResponse 无法被覆盖");
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
} catch {
|
|
815
|
+
console.warn("[Httpx-HttpxCallBack.oonLoad] 原始 response 无法被覆盖,尝试添加新的httpxResponse");
|
|
816
|
+
try {
|
|
817
|
+
Reflect.set(originResponse, "httpxResponse", httpxResponse);
|
|
818
|
+
} catch {
|
|
819
|
+
console.warn("[Httpx-HttpxCallBack.oonLoad] httpxResponse 无法被覆盖");
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
/* Stay扩展中没有finalUrl,对应的是responseURL */
|
|
824
|
+
const originResponseURL = Reflect.get(originResponse, "responseURL");
|
|
825
|
+
if (originResponse["finalUrl"] == null && originResponseURL != null) {
|
|
826
|
+
Reflect.set(originResponse, "finalUrl", originResponseURL);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/* 状态码2xx都是成功的 */
|
|
830
|
+
if (Math.floor(originResponse.status / 100) === 2) {
|
|
831
|
+
if ((await this.context.HttpxResponseHook.successResponseCallBack(originResponse, details)) == null) {
|
|
832
|
+
// reject(new Error("response is intercept with onloada"));
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
resolve({
|
|
836
|
+
data: originResponse,
|
|
837
|
+
details: details,
|
|
838
|
+
msg: "请求成功",
|
|
839
|
+
status: true,
|
|
840
|
+
statusCode: originResponse.status,
|
|
841
|
+
type: "onload",
|
|
842
|
+
});
|
|
843
|
+
} else {
|
|
844
|
+
this.context.HttpxResponseCallBack.onError(details, resolve, _reject, argsResult);
|
|
845
|
+
}
|
|
846
|
+
},
|
|
847
|
+
/**
|
|
848
|
+
* onloadstart请求开始-触发
|
|
849
|
+
* @param details 配置
|
|
850
|
+
* @param argsResult 返回的参数列表
|
|
851
|
+
*/
|
|
852
|
+
onLoadStart(details: Required<HttpxRequestOption>, argsResult: any[]) {
|
|
853
|
+
// console.log(argsResult);
|
|
854
|
+
if (typeof details?.onloadstart === "function") {
|
|
855
|
+
details.onloadstart.apply(this, argsResult);
|
|
856
|
+
} else if (typeof this.context.#defaultRequestOption?.onloadstart === "function") {
|
|
857
|
+
this.context.#defaultRequestOption.onloadstart.apply(this, argsResult);
|
|
858
|
+
}
|
|
859
|
+
},
|
|
860
|
+
/**
|
|
861
|
+
* onreadystatechange准备状态改变-触发
|
|
862
|
+
* @param details 配置
|
|
863
|
+
* @param argsResult 返回的参数列表
|
|
864
|
+
*/
|
|
865
|
+
onReadyStateChange(details: Required<HttpxRequestOption>, argsResult: any[]) {
|
|
866
|
+
// console.log(argsResult);
|
|
867
|
+
if (typeof details?.onreadystatechange === "function") {
|
|
868
|
+
details.onreadystatechange.apply(this, argsResult);
|
|
869
|
+
} else if (typeof this.context.#defaultRequestOption?.onreadystatechange === "function") {
|
|
870
|
+
this.context.#defaultRequestOption.onreadystatechange.apply(this, argsResult);
|
|
871
|
+
}
|
|
872
|
+
},
|
|
873
|
+
/**
|
|
874
|
+
* onprogress上传进度-触发
|
|
875
|
+
* @param details 配置
|
|
876
|
+
* @param argsResult 返回的参数列表
|
|
877
|
+
*/
|
|
878
|
+
onProgress(details: Required<HttpxRequestOption>, argsResult: any[]) {
|
|
879
|
+
// console.log(argsResult);
|
|
880
|
+
if (typeof details?.onprogress === "function") {
|
|
881
|
+
details.onprogress.apply(this, argsResult);
|
|
882
|
+
} else if (typeof this.context.#defaultRequestOption?.onprogress === "function") {
|
|
883
|
+
this.context.#defaultRequestOption.onprogress.apply(this, argsResult);
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
};
|
|
887
|
+
private HttpxRequest = {
|
|
888
|
+
context: this,
|
|
889
|
+
/**
|
|
890
|
+
* 发送请求
|
|
891
|
+
* @param details
|
|
892
|
+
*/
|
|
893
|
+
async request(details: Required<HttpxRequestOption>) {
|
|
894
|
+
if (this.context.#defaultInitOption.logDetails) {
|
|
895
|
+
console.log("[Httpx-HttpxRequest.request] 请求前的配置👇", details);
|
|
896
|
+
}
|
|
897
|
+
if (typeof this.context.HttpxRequestHook.beforeRequestCallBack === "function") {
|
|
898
|
+
const hookResult = await this.context.HttpxRequestHook.beforeRequestCallBack(details);
|
|
899
|
+
if (hookResult == null) {
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
if (details.fetch) {
|
|
904
|
+
// 使用fetch请求
|
|
905
|
+
const {
|
|
906
|
+
fetchOption: fetchOption,
|
|
907
|
+
fetchRequestOption: fetchRequestOption,
|
|
908
|
+
abortController,
|
|
909
|
+
} = this.context.HttpxRequestOption.handleFetchOption(details);
|
|
910
|
+
return this.fetch(fetchOption, fetchRequestOption, abortController);
|
|
911
|
+
} else {
|
|
912
|
+
// 使用GM_xmlHttpRequest请求
|
|
913
|
+
return this.xmlHttpRequest(details);
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
/**
|
|
917
|
+
* 使用油猴函数GM_xmlhttpRequest发送请求
|
|
918
|
+
* @param details
|
|
919
|
+
*/
|
|
920
|
+
xmlHttpRequest(details: Required<HttpxRequestOption>) {
|
|
921
|
+
return this.context.GM_Api.xmlHttpRequest!(details) as {
|
|
922
|
+
abort: () => void;
|
|
923
|
+
};
|
|
924
|
+
},
|
|
925
|
+
/**
|
|
926
|
+
* 使用fetch发送请求
|
|
927
|
+
* @param option
|
|
928
|
+
* @param fetchRequestOption
|
|
929
|
+
* @param abortController
|
|
930
|
+
*/
|
|
931
|
+
fetch(option: Required<HttpxRequestOption>, fetchRequestOption: RequestInit, abortController: AbortController) {
|
|
932
|
+
fetch(option.url, fetchRequestOption)
|
|
933
|
+
.then(async (fetchResponse) => {
|
|
934
|
+
/** 自定义的response */
|
|
935
|
+
const httpxResponse: HttpxResponseData<HttpxRequestOption> = {
|
|
936
|
+
isFetch: true,
|
|
937
|
+
finalUrl: fetchResponse.url,
|
|
938
|
+
readyState: 4,
|
|
939
|
+
status: fetchResponse.status,
|
|
940
|
+
statusText: fetchResponse.statusText,
|
|
941
|
+
response: "",
|
|
942
|
+
responseFetchHeaders: fetchResponse.headers,
|
|
943
|
+
responseHeaders: "",
|
|
944
|
+
responseText: "",
|
|
945
|
+
responseType: option.responseType,
|
|
946
|
+
responseXML: void 0,
|
|
947
|
+
};
|
|
948
|
+
Object.assign(httpxResponse, option.context || {});
|
|
949
|
+
|
|
950
|
+
// 把headers转为字符串
|
|
951
|
+
fetchResponse.headers.forEach((value, key) => {
|
|
952
|
+
httpxResponse.responseHeaders += `${key}: ${value}\n`;
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
/** 请求返回的类型 */
|
|
956
|
+
const fetchResponseType = fetchResponse.headers.get("Content-Type");
|
|
957
|
+
|
|
958
|
+
/* 如果需要stream,且获取到的是stream,那直接返回 */
|
|
959
|
+
if (
|
|
960
|
+
option.responseType === "stream" ||
|
|
961
|
+
(fetchResponse.headers.has("Content-Type") &&
|
|
962
|
+
fetchResponse.headers.get("Content-Type")!.includes("text/event-stream"))
|
|
963
|
+
) {
|
|
964
|
+
Reflect.set(httpxResponse, "isStream", true);
|
|
965
|
+
Reflect.set(httpxResponse, "response", fetchResponse.body);
|
|
966
|
+
Reflect.deleteProperty(httpxResponse, "responseText");
|
|
967
|
+
Reflect.deleteProperty(httpxResponse, "responseXML");
|
|
968
|
+
option.onload(httpxResponse);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/** 响应 */
|
|
973
|
+
let response: any = "";
|
|
974
|
+
/** 响应字符串 */
|
|
975
|
+
let responseText: string = "";
|
|
976
|
+
/** 响应xml文档 */
|
|
977
|
+
let responseXML: XMLDocument | string = "";
|
|
978
|
+
/** 先获取二进制数据 */
|
|
979
|
+
const arrayBuffer = await fetchResponse.arrayBuffer();
|
|
980
|
+
|
|
981
|
+
/** 数据编码 */
|
|
982
|
+
let encoding = "utf-8";
|
|
983
|
+
if (fetchResponse.headers.has("Content-Type")) {
|
|
984
|
+
const charsetMatched = fetchResponse.headers.get("Content-Type")?.match(/charset=(.+)/);
|
|
985
|
+
if (charsetMatched) {
|
|
986
|
+
encoding = charsetMatched[1];
|
|
987
|
+
encoding = encoding.toLowerCase();
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
// Failed to construct 'TextDecoder': The encoding label provided ('"UTF-8"') is invalid.
|
|
991
|
+
// 去除引号
|
|
992
|
+
encoding = encoding.replace(/('|")/gi, "");
|
|
993
|
+
// 编码
|
|
994
|
+
const textDecoder = new TextDecoder(encoding);
|
|
995
|
+
responseText = textDecoder.decode(arrayBuffer);
|
|
996
|
+
response = responseText;
|
|
997
|
+
|
|
998
|
+
if (option.responseType === "arraybuffer") {
|
|
999
|
+
// response返回格式是二进制流
|
|
1000
|
+
response = arrayBuffer;
|
|
1001
|
+
} else if (option.responseType === "blob") {
|
|
1002
|
+
// response返回格式是blob
|
|
1003
|
+
response = new Blob([arrayBuffer]);
|
|
1004
|
+
} else if (
|
|
1005
|
+
option.responseType === "json" ||
|
|
1006
|
+
(typeof fetchResponseType === "string" && fetchResponseType.includes("application/json"))
|
|
1007
|
+
) {
|
|
1008
|
+
// response返回格式是JSON格式
|
|
1009
|
+
response = CommonUtil.toJSON(responseText);
|
|
1010
|
+
} else if (option.responseType === "document" || option.responseType == null) {
|
|
1011
|
+
// response返回格式是文档格式
|
|
1012
|
+
const parser = new DOMParser();
|
|
1013
|
+
response = parser.parseFromString(responseText, "text/html");
|
|
1014
|
+
}
|
|
1015
|
+
// 转为XML结构
|
|
1016
|
+
const parser = new DOMParser();
|
|
1017
|
+
responseXML = parser.parseFromString(responseText, "text/xml");
|
|
1018
|
+
|
|
1019
|
+
httpxResponse.response = response;
|
|
1020
|
+
httpxResponse.responseText = responseText;
|
|
1021
|
+
httpxResponse.responseXML = responseXML;
|
|
1022
|
+
|
|
1023
|
+
// 执行回调
|
|
1024
|
+
option.onload(httpxResponse);
|
|
1025
|
+
})
|
|
1026
|
+
.catch((error: any) => {
|
|
1027
|
+
if (error.name === "AbortError") {
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
option.onerror({
|
|
1031
|
+
isFetch: true,
|
|
1032
|
+
finalUrl: option.url,
|
|
1033
|
+
readyState: 4,
|
|
1034
|
+
status: 0,
|
|
1035
|
+
statusText: "",
|
|
1036
|
+
responseHeaders: "",
|
|
1037
|
+
responseText: "",
|
|
1038
|
+
error: error,
|
|
1039
|
+
});
|
|
1040
|
+
});
|
|
1041
|
+
option.onloadstart({
|
|
1042
|
+
isFetch: true,
|
|
1043
|
+
finalUrl: option.url,
|
|
1044
|
+
readyState: 1,
|
|
1045
|
+
responseHeaders: "",
|
|
1046
|
+
responseText: "",
|
|
1047
|
+
status: 0,
|
|
1048
|
+
statusText: "",
|
|
1049
|
+
});
|
|
1050
|
+
return {
|
|
1051
|
+
abort() {
|
|
1052
|
+
abortController.abort();
|
|
1053
|
+
},
|
|
1054
|
+
};
|
|
1055
|
+
},
|
|
1056
|
+
};
|
|
1057
|
+
/**
|
|
1058
|
+
* 默认配置
|
|
1059
|
+
*/
|
|
1060
|
+
#defaultRequestOption = <HttpxRequestOption>{
|
|
1061
|
+
url: void 0 as undefined | string,
|
|
1062
|
+
timeout: 5000,
|
|
1063
|
+
async: false,
|
|
1064
|
+
responseType: void 0,
|
|
1065
|
+
headers: void 0,
|
|
1066
|
+
data: void 0,
|
|
1067
|
+
redirect: void 0,
|
|
1068
|
+
cookie: void 0,
|
|
1069
|
+
cookiePartition: void 0,
|
|
1070
|
+
binary: void 0,
|
|
1071
|
+
nocache: void 0,
|
|
1072
|
+
revalidate: void 0,
|
|
1073
|
+
context: void 0,
|
|
1074
|
+
overrideMimeType: void 0,
|
|
1075
|
+
anonymous: void 0,
|
|
1076
|
+
fetch: void 0,
|
|
1077
|
+
fetchInit: void 0,
|
|
1078
|
+
allowInterceptConfig: {
|
|
1079
|
+
beforeRequest: true,
|
|
1080
|
+
afterResponseSuccess: true,
|
|
1081
|
+
afterResponseError: true,
|
|
1082
|
+
},
|
|
1083
|
+
user: void 0,
|
|
1084
|
+
password: void 0,
|
|
1085
|
+
onabort() {},
|
|
1086
|
+
onerror() {},
|
|
1087
|
+
ontimeout() {},
|
|
1088
|
+
onloadstart() {},
|
|
1089
|
+
onreadystatechange() {},
|
|
1090
|
+
onprogress() {},
|
|
1091
|
+
};
|
|
1092
|
+
/**
|
|
1093
|
+
* 实例化的默认配置
|
|
1094
|
+
*/
|
|
1095
|
+
#defaultInitOption = {
|
|
1096
|
+
/**
|
|
1097
|
+
* `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
|
|
1098
|
+
*/
|
|
1099
|
+
baseURL: void 0 as undefined | string,
|
|
1100
|
+
/**
|
|
1101
|
+
* 当前使用请求时,输出请求的配置,一般用于DEBUG|DEV
|
|
1102
|
+
*/
|
|
1103
|
+
logDetails: false,
|
|
1104
|
+
};
|
|
1105
|
+
/**
|
|
1106
|
+
* 实例化
|
|
1107
|
+
* @param option 初始化配置
|
|
1108
|
+
*/
|
|
1109
|
+
constructor(option: Partial<HttpxInitOption> = {}) {
|
|
1110
|
+
if (typeof option.xmlHttpRequest !== "function") {
|
|
1111
|
+
console.warn(
|
|
1112
|
+
"[Httpx-constructor] 未传入GM_xmlhttpRequest函数或传入的GM_xmlhttpRequest不是Function,将默认使用window.fetch"
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
CommonUtil.coverObjectFunctionThis(this);
|
|
1116
|
+
this.interceptors.request.context = this;
|
|
1117
|
+
this.interceptors.response.context = this;
|
|
1118
|
+
this.config(option);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* 覆盖当前配置
|
|
1122
|
+
* @param option
|
|
1123
|
+
*/
|
|
1124
|
+
config(option: Partial<HttpxInitOption> = {}) {
|
|
1125
|
+
if (typeof option.xmlHttpRequest === "function") {
|
|
1126
|
+
this.GM_Api.xmlHttpRequest = option.xmlHttpRequest;
|
|
1127
|
+
}
|
|
1128
|
+
this.#defaultRequestOption = CommonUtil.assign(this.#defaultRequestOption, option);
|
|
1129
|
+
this.#defaultInitOption = CommonUtil.assign(this.#defaultInitOption, option);
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* 拦截器
|
|
1133
|
+
*/
|
|
1134
|
+
interceptors = {
|
|
1135
|
+
/**
|
|
1136
|
+
* 请求拦截器
|
|
1137
|
+
*/
|
|
1138
|
+
request: {
|
|
1139
|
+
context: null as any as Httpx,
|
|
1140
|
+
/**
|
|
1141
|
+
* 添加拦截器
|
|
1142
|
+
* @param fn 设置的请求前回调函数,如果返回配置,则使用返回的配置,如果返回null|undefined,则阻止请求
|
|
1143
|
+
*/
|
|
1144
|
+
use(fn: <T extends Required<HttpxRequestOption>>(details: T) => void | T | Promise<void | T>) {
|
|
1145
|
+
if (typeof fn !== "function") {
|
|
1146
|
+
console.warn("[Httpx-interceptors-request] 请传入拦截器函数");
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
return this.context.HttpxRequestHook.add(fn);
|
|
1150
|
+
},
|
|
1151
|
+
/**
|
|
1152
|
+
* 移除拦截器
|
|
1153
|
+
* @param id 通过use返回的id
|
|
1154
|
+
*/
|
|
1155
|
+
eject(id: string) {
|
|
1156
|
+
return this.context.HttpxRequestHook.delete(id);
|
|
1157
|
+
},
|
|
1158
|
+
/**
|
|
1159
|
+
* 移除所有拦截器
|
|
1160
|
+
*/
|
|
1161
|
+
ejectAll() {
|
|
1162
|
+
this.context.HttpxRequestHook.clearAll();
|
|
1163
|
+
},
|
|
1164
|
+
},
|
|
1165
|
+
/**
|
|
1166
|
+
* 响应拦截器
|
|
1167
|
+
*/
|
|
1168
|
+
response: {
|
|
1169
|
+
context: null as any as Httpx,
|
|
1170
|
+
/**
|
|
1171
|
+
* 添加拦截器
|
|
1172
|
+
* @param successFn 设置的响应后回调函数,如果返回响应,则使用返回的响应,如果返回null|undefined,则阻止响应
|
|
1173
|
+
* + 2xx 范围内的状态码都会触发该函数
|
|
1174
|
+
* @param errorFn 设置的响应后回调函数,如果返回响应,则使用返回的响应,如果返回null|undefined,则阻止响应
|
|
1175
|
+
* + 超出 2xx 范围的状态码都会触发该函数
|
|
1176
|
+
*/
|
|
1177
|
+
use(
|
|
1178
|
+
successFn?: <T extends HttpxResponseData<HttpxRequestOption>>(
|
|
1179
|
+
response: T,
|
|
1180
|
+
details: HttpxRequestOption
|
|
1181
|
+
) => void | T,
|
|
1182
|
+
errorFn?: <T extends HttpxHookErrorData>(data: T) => void | T | Promise<void | T>
|
|
1183
|
+
) {
|
|
1184
|
+
if (typeof successFn !== "function" && typeof errorFn !== "function") {
|
|
1185
|
+
console.warn("[Httpx-interceptors-response] 必须传入一个拦截器函数");
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
return this.context.HttpxResponseHook.add(successFn!, errorFn!);
|
|
1189
|
+
},
|
|
1190
|
+
/**
|
|
1191
|
+
* 移除拦截器
|
|
1192
|
+
* @param id 通过use返回的id
|
|
1193
|
+
*/
|
|
1194
|
+
eject(id: string) {
|
|
1195
|
+
return this.context.HttpxResponseHook.delete(id);
|
|
1196
|
+
},
|
|
1197
|
+
/**
|
|
1198
|
+
* 移除所有拦截器
|
|
1199
|
+
*/
|
|
1200
|
+
ejectAll() {
|
|
1201
|
+
this.context.HttpxResponseHook.clearAll();
|
|
1202
|
+
},
|
|
1203
|
+
},
|
|
1204
|
+
};
|
|
1205
|
+
/**
|
|
1206
|
+
* 修改xmlHttpRequest
|
|
1207
|
+
* @param httpRequest 网络请求函数
|
|
1208
|
+
*/
|
|
1209
|
+
setXMLHttpRequest(httpRequest: (...args: any[]) => any) {
|
|
1210
|
+
this.GM_Api.xmlHttpRequest = httpRequest;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* GET 请求
|
|
1214
|
+
* @param details 配置
|
|
1215
|
+
*/
|
|
1216
|
+
get<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1217
|
+
/**
|
|
1218
|
+
* GET 请求
|
|
1219
|
+
* @param url 请求的url
|
|
1220
|
+
* @param details 配置
|
|
1221
|
+
*/
|
|
1222
|
+
get<T extends Omit<HttpxRequestOption, "url">>(
|
|
1223
|
+
url: string,
|
|
1224
|
+
details?: T
|
|
1225
|
+
): HttpxPromise<
|
|
1226
|
+
HttpxResponse<
|
|
1227
|
+
T & {
|
|
1228
|
+
/**
|
|
1229
|
+
* 请求的url
|
|
1230
|
+
*/
|
|
1231
|
+
url: string;
|
|
1232
|
+
}
|
|
1233
|
+
>
|
|
1234
|
+
>;
|
|
1235
|
+
/**
|
|
1236
|
+
* GET 请求
|
|
1237
|
+
* @param url 请求的url
|
|
1238
|
+
* @param details 配置
|
|
1239
|
+
*/
|
|
1240
|
+
get(...args: (string | HttpxRequestOption)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1241
|
+
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1242
|
+
useRequestOption.method = "GET";
|
|
1243
|
+
return this.request(useRequestOption, (option) => {
|
|
1244
|
+
Reflect.deleteProperty(option, "onprogress");
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* POST 请求
|
|
1249
|
+
* @param details 配置
|
|
1250
|
+
*/
|
|
1251
|
+
post<T extends HttpxRequestOption>(details?: T): HttpxPromise<HttpxResponse<T>>;
|
|
1252
|
+
/**
|
|
1253
|
+
* POST 请求
|
|
1254
|
+
* @param url 请求的url
|
|
1255
|
+
* @param details 配置
|
|
1256
|
+
*/
|
|
1257
|
+
post<T extends Omit<HttpxRequestOption, "url">>(
|
|
1258
|
+
url: string,
|
|
1259
|
+
details?: T
|
|
1260
|
+
): HttpxPromise<
|
|
1261
|
+
HttpxResponse<
|
|
1262
|
+
T & {
|
|
1263
|
+
/**
|
|
1264
|
+
* 请求的url
|
|
1265
|
+
*/
|
|
1266
|
+
url: string;
|
|
1267
|
+
}
|
|
1268
|
+
>
|
|
1269
|
+
>;
|
|
1270
|
+
/**
|
|
1271
|
+
* POST 请求
|
|
1272
|
+
*/
|
|
1273
|
+
post(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1274
|
+
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1275
|
+
useRequestOption.method = "POST";
|
|
1276
|
+
return this.request(useRequestOption);
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* HEAD 请求
|
|
1280
|
+
* @param details 配置
|
|
1281
|
+
*/
|
|
1282
|
+
head<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1283
|
+
/**
|
|
1284
|
+
* HEAD 请求
|
|
1285
|
+
* @param url 请求的url
|
|
1286
|
+
* @param details 配置
|
|
1287
|
+
*/
|
|
1288
|
+
head<T extends Omit<HttpxRequestOption, "url">>(
|
|
1289
|
+
url: string,
|
|
1290
|
+
details?: T
|
|
1291
|
+
): HttpxPromise<
|
|
1292
|
+
HttpxResponse<
|
|
1293
|
+
T & {
|
|
1294
|
+
/**
|
|
1295
|
+
* 请求的url
|
|
1296
|
+
*/
|
|
1297
|
+
url: string;
|
|
1298
|
+
}
|
|
1299
|
+
>
|
|
1300
|
+
>;
|
|
1301
|
+
/**
|
|
1302
|
+
* HEAD 请求
|
|
1303
|
+
*/
|
|
1304
|
+
head(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1305
|
+
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1306
|
+
useRequestOption.method = "HEAD";
|
|
1307
|
+
return this.request(useRequestOption, (option) => {
|
|
1308
|
+
Reflect.deleteProperty(option, "onprogress");
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* OPTIONS 请求
|
|
1313
|
+
* @param details 配置
|
|
1314
|
+
*/
|
|
1315
|
+
options<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1316
|
+
/**
|
|
1317
|
+
* OPTIONS 请求
|
|
1318
|
+
* @param url 请求的url
|
|
1319
|
+
* @param details 配置
|
|
1320
|
+
*/
|
|
1321
|
+
options<T extends Omit<HttpxRequestOption, "url">>(
|
|
1322
|
+
url: string,
|
|
1323
|
+
details?: T
|
|
1324
|
+
): HttpxPromise<
|
|
1325
|
+
HttpxResponse<
|
|
1326
|
+
T & {
|
|
1327
|
+
/**
|
|
1328
|
+
* 请求的url
|
|
1329
|
+
*/
|
|
1330
|
+
url: string;
|
|
1331
|
+
}
|
|
1332
|
+
>
|
|
1333
|
+
>;
|
|
1334
|
+
/**
|
|
1335
|
+
* OPTIONS 请求
|
|
1336
|
+
*/
|
|
1337
|
+
options(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1338
|
+
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1339
|
+
useRequestOption.method = "OPTIONS";
|
|
1340
|
+
return this.request(useRequestOption, (option) => {
|
|
1341
|
+
Reflect.deleteProperty(option, "onprogress");
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* DELETE 请求
|
|
1346
|
+
* @param details 配置
|
|
1347
|
+
*/
|
|
1348
|
+
delete<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1349
|
+
/**
|
|
1350
|
+
* DELETE 请求
|
|
1351
|
+
* @param url 请求的url
|
|
1352
|
+
* @param details 配置
|
|
1353
|
+
*/
|
|
1354
|
+
delete<T extends Omit<HttpxRequestOption, "url">>(
|
|
1355
|
+
url: string,
|
|
1356
|
+
details?: T
|
|
1357
|
+
): HttpxPromise<
|
|
1358
|
+
HttpxResponse<
|
|
1359
|
+
T & {
|
|
1360
|
+
/**
|
|
1361
|
+
* 请求的url
|
|
1362
|
+
*/
|
|
1363
|
+
url: string;
|
|
1364
|
+
}
|
|
1365
|
+
>
|
|
1366
|
+
>;
|
|
1367
|
+
/**
|
|
1368
|
+
* DELETE 请求
|
|
1369
|
+
*/
|
|
1370
|
+
delete(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1371
|
+
const useRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1372
|
+
useRequestOption.method = "DELETE";
|
|
1373
|
+
return this.request(useRequestOption, (option) => {
|
|
1374
|
+
Reflect.deleteProperty(option, "onprogress");
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* PUT 请求
|
|
1379
|
+
* @param details 配置
|
|
1380
|
+
*/
|
|
1381
|
+
put<T extends HttpxRequestOption>(details: T): HttpxPromise<HttpxResponse<T>>;
|
|
1382
|
+
/**
|
|
1383
|
+
* PUT 请求
|
|
1384
|
+
* @param url 请求的url
|
|
1385
|
+
* @param details 配置
|
|
1386
|
+
*/
|
|
1387
|
+
put<T extends Omit<HttpxRequestOption, "url">>(
|
|
1388
|
+
url: string,
|
|
1389
|
+
details?: T
|
|
1390
|
+
): HttpxPromise<
|
|
1391
|
+
HttpxResponse<
|
|
1392
|
+
T & {
|
|
1393
|
+
/**
|
|
1394
|
+
* 请求的url
|
|
1395
|
+
*/
|
|
1396
|
+
url: string;
|
|
1397
|
+
}
|
|
1398
|
+
>
|
|
1399
|
+
>;
|
|
1400
|
+
/**
|
|
1401
|
+
* PUT 请求
|
|
1402
|
+
*/
|
|
1403
|
+
put(...args: (HttpxRequestOption | string)[]): HttpxPromise<HttpxResponse<HttpxRequestOption>> {
|
|
1404
|
+
const userRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(...args);
|
|
1405
|
+
userRequestOption.method = "PUT";
|
|
1406
|
+
return this.request(userRequestOption);
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* 发送请求
|
|
1410
|
+
* @param details 配置
|
|
1411
|
+
* @param beforeRequestOption 处理请求前的配置
|
|
1412
|
+
*/
|
|
1413
|
+
request<T extends HttpxRequestOption>(
|
|
1414
|
+
details: T,
|
|
1415
|
+
beforeRequestOption?: (option: Required<T | HttpxRequestOption>) => void
|
|
1416
|
+
): HttpxPromise<HttpxResponse<T>> {
|
|
1417
|
+
// 对请求的参数进行合并处理
|
|
1418
|
+
const userRequestOption = this.HttpxRequestOption.handleBeforeRequestOptionArgs(details);
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* 取消请求
|
|
1422
|
+
*/
|
|
1423
|
+
let abortFn: ((...args: any[]) => any) | null = null;
|
|
1424
|
+
const promise = new globalThis.Promise<HttpxResponse<HttpxRequestOption>>(async (resolve, reject) => {
|
|
1425
|
+
// 请求配置
|
|
1426
|
+
let requestOption = this.HttpxRequestOption.getRequestOption(
|
|
1427
|
+
userRequestOption.method!,
|
|
1428
|
+
userRequestOption,
|
|
1429
|
+
(resultOption) => {
|
|
1430
|
+
resolve(resultOption);
|
|
1431
|
+
},
|
|
1432
|
+
(...args: any[]) => {
|
|
1433
|
+
reject(...args);
|
|
1434
|
+
}
|
|
1435
|
+
);
|
|
1436
|
+
requestOption = this.HttpxRequestOption.removeRequestNullOption(requestOption);
|
|
1437
|
+
if (typeof beforeRequestOption === "function") {
|
|
1438
|
+
beforeRequestOption(requestOption as Required<T>);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
// 处理重试逻辑
|
|
1442
|
+
const requestResult = await this.HttpxRequest.request(requestOption);
|
|
1443
|
+
if (requestResult != null && typeof requestResult.abort === "function") {
|
|
1444
|
+
abortFn = () => {
|
|
1445
|
+
// 取消请求
|
|
1446
|
+
requestResult.abort();
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
}) as HttpxPromise<HttpxResponse<T>>;
|
|
1450
|
+
promise.abort = () => {
|
|
1451
|
+
if (typeof abortFn === "function") {
|
|
1452
|
+
abortFn();
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
return promise;
|
|
1456
|
+
}
|
|
1457
|
+
}
|