@whitesev/utils 1.5.6 → 1.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.amd.js +259 -152
- package/dist/index.amd.js.map +1 -1
- package/dist/index.cjs.js +259 -152
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +259 -152
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +259 -152
- package/dist/index.iife.js.map +1 -1
- package/dist/index.system.js +259 -152
- package/dist/index.system.js.map +1 -1
- package/dist/index.umd.js +259 -152
- package/dist/index.umd.js.map +1 -1
- package/dist/src/AjaxHookerType.d.ts +147 -0
- package/dist/src/Httpx.d.ts +1 -1
- package/dist/src/Utils.d.ts +1 -1
- package/package.json +1 -1
- package/src/{ajaxHooker/index.d.ts → AjaxHookerType.ts} +2 -0
- package/src/Httpx.ts +2 -1
- package/src/Utils.ts +1 -2
- package/src/ajaxHooker/ajaxHooker.js +261 -155
|
@@ -5,28 +5,45 @@
|
|
|
5
5
|
// @updateLog xhr事件增加currentTarget劫持。
|
|
6
6
|
// @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
|
|
7
7
|
|
|
8
|
-
const AjaxHooker = function () {
|
|
9
|
-
return function() {
|
|
10
|
-
|
|
11
|
-
const version =
|
|
8
|
+
export const AjaxHooker = function () {
|
|
9
|
+
return (function () {
|
|
10
|
+
"use strict";
|
|
11
|
+
const version = "1.4.3";
|
|
12
12
|
const hookInst = {
|
|
13
13
|
hookFns: [],
|
|
14
|
-
filters: []
|
|
14
|
+
filters: [],
|
|
15
15
|
};
|
|
16
16
|
const win = window.unsafeWindow || document.defaultView || window;
|
|
17
17
|
let winAh = win.__ajaxHooker;
|
|
18
18
|
const resProto = win.Response.prototype;
|
|
19
|
-
const xhrResponses = [
|
|
20
|
-
const fetchResponses = [
|
|
21
|
-
const fetchInitProps = [
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
const xhrResponses = ["response", "responseText", "responseXML"];
|
|
20
|
+
const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
|
|
21
|
+
const fetchInitProps = [
|
|
22
|
+
"method",
|
|
23
|
+
"headers",
|
|
24
|
+
"body",
|
|
25
|
+
"mode",
|
|
26
|
+
"credentials",
|
|
27
|
+
"cache",
|
|
28
|
+
"redirect",
|
|
29
|
+
"referrer",
|
|
30
|
+
"referrerPolicy",
|
|
31
|
+
"integrity",
|
|
32
|
+
"keepalive",
|
|
33
|
+
"signal",
|
|
34
|
+
"priority",
|
|
35
|
+
];
|
|
36
|
+
const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
|
|
37
|
+
const getType = {}.toString.call.bind({}.toString);
|
|
25
38
|
const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
|
|
26
39
|
const emptyFn = () => {};
|
|
27
|
-
const errorFn = e => console.error(e);
|
|
40
|
+
const errorFn = (e) => console.error(e);
|
|
28
41
|
function isThenable(obj) {
|
|
29
|
-
return
|
|
42
|
+
return (
|
|
43
|
+
obj &&
|
|
44
|
+
["object", "function"].includes(typeof obj) &&
|
|
45
|
+
typeof obj.then === "function"
|
|
46
|
+
);
|
|
30
47
|
}
|
|
31
48
|
function catchError(fn, ...args) {
|
|
32
49
|
try {
|
|
@@ -42,7 +59,7 @@ const AjaxHooker = function () {
|
|
|
42
59
|
configurable: true,
|
|
43
60
|
enumerable: true,
|
|
44
61
|
get: getter,
|
|
45
|
-
set: setter
|
|
62
|
+
set: setter,
|
|
46
63
|
});
|
|
47
64
|
}
|
|
48
65
|
function readonly(obj, prop, value = obj[prop]) {
|
|
@@ -53,27 +70,28 @@ const AjaxHooker = function () {
|
|
|
53
70
|
configurable: true,
|
|
54
71
|
enumerable: true,
|
|
55
72
|
writable: true,
|
|
56
|
-
value: value
|
|
73
|
+
value: value,
|
|
57
74
|
});
|
|
58
75
|
}
|
|
59
76
|
function parseHeaders(obj) {
|
|
60
77
|
const headers = {};
|
|
61
78
|
switch (getType(obj)) {
|
|
62
|
-
case
|
|
79
|
+
case "[object String]":
|
|
63
80
|
for (const line of obj.trim().split(/[\r\n]+/)) {
|
|
64
81
|
const [header, value] = line.split(/\s*:\s*/);
|
|
65
82
|
if (!header) break;
|
|
66
83
|
const lheader = header.toLowerCase();
|
|
67
|
-
headers[lheader] =
|
|
84
|
+
headers[lheader] =
|
|
85
|
+
lheader in headers ? `${headers[lheader]}, ${value}` : value;
|
|
68
86
|
}
|
|
69
87
|
break;
|
|
70
|
-
case
|
|
88
|
+
case "[object Headers]":
|
|
71
89
|
for (const [key, val] of obj) {
|
|
72
90
|
headers[key] = val;
|
|
73
91
|
}
|
|
74
92
|
break;
|
|
75
|
-
case
|
|
76
|
-
return {...obj};
|
|
93
|
+
case "[object Object]":
|
|
94
|
+
return { ...obj };
|
|
77
95
|
}
|
|
78
96
|
return headers;
|
|
79
97
|
}
|
|
@@ -89,104 +107,142 @@ const AjaxHooker = function () {
|
|
|
89
107
|
class AHRequest {
|
|
90
108
|
constructor(request) {
|
|
91
109
|
this.request = request;
|
|
92
|
-
this.requestClone = {...this.request};
|
|
110
|
+
this.requestClone = { ...this.request };
|
|
93
111
|
}
|
|
94
112
|
shouldFilter(filters) {
|
|
95
|
-
const {type, url, method, async} = this.request;
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
const { type, url, method, async } = this.request;
|
|
114
|
+
return (
|
|
115
|
+
filters.length &&
|
|
116
|
+
!filters.find((obj) => {
|
|
117
|
+
switch (true) {
|
|
118
|
+
case obj.type && obj.type !== type:
|
|
119
|
+
case getType(obj.url) === "[object String]" &&
|
|
120
|
+
!url.includes(obj.url):
|
|
121
|
+
case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
|
|
122
|
+
case obj.method &&
|
|
123
|
+
obj.method.toUpperCase() !== method.toUpperCase():
|
|
124
|
+
case "async" in obj && obj.async !== async:
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
})
|
|
129
|
+
);
|
|
107
130
|
}
|
|
108
131
|
waitForRequestKeys() {
|
|
109
|
-
const requestKeys = [
|
|
132
|
+
const requestKeys = ["url", "method", "abort", "headers", "data"];
|
|
110
133
|
if (!this.request.async) {
|
|
111
|
-
win.__ajaxHooker.hookInsts.forEach(({hookFns, filters}) => {
|
|
134
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
112
135
|
if (this.shouldFilter(filters)) return;
|
|
113
|
-
hookFns.forEach(fn => {
|
|
114
|
-
if (getType(fn) ===
|
|
136
|
+
hookFns.forEach((fn) => {
|
|
137
|
+
if (getType(fn) === "[object Function]")
|
|
138
|
+
catchError(fn, this.request);
|
|
115
139
|
});
|
|
116
|
-
requestKeys.forEach(key => {
|
|
117
|
-
if (isThenable(this.request[key]))
|
|
140
|
+
requestKeys.forEach((key) => {
|
|
141
|
+
if (isThenable(this.request[key]))
|
|
142
|
+
this.request[key] = this.requestClone[key];
|
|
118
143
|
});
|
|
119
144
|
});
|
|
120
145
|
return new SyncThenable();
|
|
121
146
|
}
|
|
122
147
|
const promises = [];
|
|
123
|
-
win.__ajaxHooker.hookInsts.forEach(({hookFns, filters}) => {
|
|
148
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
124
149
|
if (this.shouldFilter(filters)) return;
|
|
125
|
-
promises.push(
|
|
126
|
-
Promise.all(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
150
|
+
promises.push(
|
|
151
|
+
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
152
|
+
() =>
|
|
153
|
+
Promise.all(
|
|
154
|
+
requestKeys.map((key) =>
|
|
155
|
+
Promise.resolve(this.request[key]).then(
|
|
156
|
+
(val) => (this.request[key] = val),
|
|
157
|
+
() => (this.request[key] = this.requestClone[key])
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
);
|
|
131
163
|
});
|
|
132
164
|
return Promise.all(promises);
|
|
133
165
|
}
|
|
134
166
|
waitForResponseKeys(response) {
|
|
135
|
-
const responseKeys =
|
|
167
|
+
const responseKeys =
|
|
168
|
+
this.request.type === "xhr" ? xhrResponses : fetchResponses;
|
|
136
169
|
if (!this.request.async) {
|
|
137
|
-
if (getType(this.request.response) ===
|
|
170
|
+
if (getType(this.request.response) === "[object Function]") {
|
|
138
171
|
catchError(this.request.response, response);
|
|
139
|
-
responseKeys.forEach(key => {
|
|
140
|
-
if (
|
|
172
|
+
responseKeys.forEach((key) => {
|
|
173
|
+
if (
|
|
174
|
+
"get" in getDescriptor(response, key) ||
|
|
175
|
+
isThenable(response[key])
|
|
176
|
+
) {
|
|
141
177
|
delete response[key];
|
|
142
178
|
}
|
|
143
179
|
});
|
|
144
180
|
}
|
|
145
181
|
return new SyncThenable();
|
|
146
182
|
}
|
|
147
|
-
return Promise.resolve(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
183
|
+
return Promise.resolve(
|
|
184
|
+
catchError(this.request.response, response)
|
|
185
|
+
).then(() =>
|
|
186
|
+
Promise.all(
|
|
187
|
+
responseKeys.map((key) => {
|
|
188
|
+
const descriptor = getDescriptor(response, key);
|
|
189
|
+
if (descriptor && "value" in descriptor) {
|
|
190
|
+
return Promise.resolve(descriptor.value).then(
|
|
191
|
+
(val) => (response[key] = val),
|
|
192
|
+
() => delete response[key]
|
|
193
|
+
);
|
|
194
|
+
} else {
|
|
195
|
+
delete response[key];
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
)
|
|
159
199
|
);
|
|
160
200
|
}
|
|
161
201
|
}
|
|
162
202
|
const proxyHandler = {
|
|
163
203
|
get(target, prop) {
|
|
164
204
|
const descriptor = getDescriptor(target, prop);
|
|
165
|
-
if (
|
|
205
|
+
if (
|
|
206
|
+
descriptor &&
|
|
207
|
+
!descriptor.configurable &&
|
|
208
|
+
!descriptor.writable &&
|
|
209
|
+
!descriptor.get
|
|
210
|
+
)
|
|
211
|
+
return target[prop];
|
|
166
212
|
const ah = target.__ajaxHooker;
|
|
167
213
|
if (ah && ah.proxyProps) {
|
|
168
214
|
if (prop in ah.proxyProps) {
|
|
169
215
|
const pDescriptor = ah.proxyProps[prop];
|
|
170
|
-
if (
|
|
171
|
-
if (typeof pDescriptor.value ===
|
|
216
|
+
if ("get" in pDescriptor) return pDescriptor.get();
|
|
217
|
+
if (typeof pDescriptor.value === "function")
|
|
218
|
+
return pDescriptor.value.bind(ah);
|
|
172
219
|
return pDescriptor.value;
|
|
173
220
|
}
|
|
174
|
-
if (typeof target[prop] ===
|
|
221
|
+
if (typeof target[prop] === "function")
|
|
222
|
+
return target[prop].bind(target);
|
|
175
223
|
}
|
|
176
224
|
return target[prop];
|
|
177
225
|
},
|
|
178
226
|
set(target, prop, value) {
|
|
179
227
|
const descriptor = getDescriptor(target, prop);
|
|
180
|
-
if (
|
|
228
|
+
if (
|
|
229
|
+
descriptor &&
|
|
230
|
+
!descriptor.configurable &&
|
|
231
|
+
!descriptor.writable &&
|
|
232
|
+
!descriptor.set
|
|
233
|
+
)
|
|
234
|
+
return true;
|
|
181
235
|
const ah = target.__ajaxHooker;
|
|
182
236
|
if (ah && ah.proxyProps && prop in ah.proxyProps) {
|
|
183
237
|
const pDescriptor = ah.proxyProps[prop];
|
|
184
|
-
pDescriptor.set
|
|
238
|
+
pDescriptor.set
|
|
239
|
+
? pDescriptor.set(value)
|
|
240
|
+
: (pDescriptor.value = value);
|
|
185
241
|
} else {
|
|
186
242
|
target[prop] = value;
|
|
187
243
|
}
|
|
188
244
|
return true;
|
|
189
|
-
}
|
|
245
|
+
},
|
|
190
246
|
};
|
|
191
247
|
class XhrHooker {
|
|
192
248
|
constructor(xhr) {
|
|
@@ -196,86 +252,113 @@ const AjaxHooker = function () {
|
|
|
196
252
|
proxyXhr: new Proxy(xhr, proxyHandler),
|
|
197
253
|
resThenable: new SyncThenable(),
|
|
198
254
|
proxyProps: {},
|
|
199
|
-
proxyEvents: {}
|
|
255
|
+
proxyEvents: {},
|
|
200
256
|
});
|
|
201
|
-
xhr.addEventListener(
|
|
202
|
-
if (
|
|
257
|
+
xhr.addEventListener("readystatechange", (e) => {
|
|
258
|
+
if (
|
|
259
|
+
ah.proxyXhr.readyState === 4 &&
|
|
260
|
+
ah.request &&
|
|
261
|
+
typeof ah.request.response === "function"
|
|
262
|
+
) {
|
|
203
263
|
const response = {
|
|
204
264
|
finalUrl: ah.proxyXhr.responseURL,
|
|
205
265
|
status: ah.proxyXhr.status,
|
|
206
|
-
responseHeaders: parseHeaders(
|
|
266
|
+
responseHeaders: parseHeaders(
|
|
267
|
+
ah.proxyXhr.getAllResponseHeaders()
|
|
268
|
+
),
|
|
207
269
|
};
|
|
208
270
|
const tempValues = {};
|
|
209
271
|
for (const key of xhrResponses) {
|
|
210
272
|
try {
|
|
211
273
|
tempValues[key] = ah.originalXhr[key];
|
|
212
274
|
} catch (err) {}
|
|
213
|
-
defineProp(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
275
|
+
defineProp(
|
|
276
|
+
response,
|
|
277
|
+
key,
|
|
278
|
+
() => {
|
|
279
|
+
return (response[key] = tempValues[key]);
|
|
280
|
+
},
|
|
281
|
+
(val) => {
|
|
282
|
+
delete response[key];
|
|
283
|
+
response[key] = val;
|
|
284
|
+
}
|
|
285
|
+
);
|
|
219
286
|
}
|
|
220
|
-
ah.resThenable = new AHRequest(ah.request)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
287
|
+
ah.resThenable = new AHRequest(ah.request)
|
|
288
|
+
.waitForResponseKeys(response)
|
|
289
|
+
.then(() => {
|
|
290
|
+
for (const key of xhrResponses) {
|
|
291
|
+
ah.proxyProps[key] = {
|
|
292
|
+
get: () => {
|
|
293
|
+
if (!(key in response)) response[key] = tempValues[key];
|
|
294
|
+
return response[key];
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
});
|
|
228
299
|
}
|
|
229
300
|
ah.dispatchEvent(e);
|
|
230
301
|
});
|
|
231
|
-
xhr.addEventListener(
|
|
232
|
-
xhr.addEventListener(
|
|
302
|
+
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
303
|
+
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
233
304
|
for (const evt of xhrAsyncEvents) {
|
|
234
|
-
const onEvt =
|
|
305
|
+
const onEvt = "on" + evt;
|
|
235
306
|
ah.proxyProps[onEvt] = {
|
|
236
307
|
get: () => ah.proxyEvents[onEvt] || null,
|
|
237
|
-
set: val => ah.addEvent(onEvt, val)
|
|
308
|
+
set: (val) => ah.addEvent(onEvt, val),
|
|
238
309
|
};
|
|
239
310
|
}
|
|
240
|
-
for (const method of [
|
|
241
|
-
|
|
311
|
+
for (const method of [
|
|
312
|
+
"setRequestHeader",
|
|
313
|
+
"addEventListener",
|
|
314
|
+
"removeEventListener",
|
|
315
|
+
"open",
|
|
316
|
+
"send",
|
|
317
|
+
]) {
|
|
318
|
+
ah.proxyProps[method] = { value: ah[method] };
|
|
242
319
|
}
|
|
243
320
|
}
|
|
244
321
|
toJSON() {} // Converting circular structure to JSON
|
|
245
322
|
addEvent(type, event) {
|
|
246
|
-
if (type.startsWith(
|
|
247
|
-
this.proxyEvents[type] = typeof event ===
|
|
323
|
+
if (type.startsWith("on")) {
|
|
324
|
+
this.proxyEvents[type] = typeof event === "function" ? event : null;
|
|
248
325
|
} else {
|
|
249
|
-
if (typeof event ===
|
|
250
|
-
|
|
326
|
+
if (typeof event === "object" && event !== null)
|
|
327
|
+
event = event.handleEvent;
|
|
328
|
+
if (typeof event !== "function") return;
|
|
251
329
|
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
252
330
|
this.proxyEvents[type].add(event);
|
|
253
331
|
}
|
|
254
332
|
}
|
|
255
333
|
removeEvent(type, event) {
|
|
256
|
-
if (type.startsWith(
|
|
334
|
+
if (type.startsWith("on")) {
|
|
257
335
|
this.proxyEvents[type] = null;
|
|
258
336
|
} else {
|
|
259
|
-
if (typeof event ===
|
|
337
|
+
if (typeof event === "object" && event !== null)
|
|
338
|
+
event = event.handleEvent;
|
|
260
339
|
this.proxyEvents[type] && this.proxyEvents[type].delete(event);
|
|
261
340
|
}
|
|
262
341
|
}
|
|
263
342
|
dispatchEvent(e) {
|
|
264
343
|
e.stopImmediatePropagation = stopImmediatePropagation;
|
|
265
|
-
defineProp(e,
|
|
266
|
-
defineProp(e,
|
|
267
|
-
this.proxyEvents[e.type] &&
|
|
268
|
-
this.
|
|
269
|
-
|
|
344
|
+
defineProp(e, "target", () => this.proxyXhr);
|
|
345
|
+
defineProp(e, "currentTarget", () => this.proxyXhr);
|
|
346
|
+
this.proxyEvents[e.type] &&
|
|
347
|
+
this.proxyEvents[e.type].forEach((fn) => {
|
|
348
|
+
this.resThenable.then(
|
|
349
|
+
() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e)
|
|
350
|
+
);
|
|
351
|
+
});
|
|
270
352
|
if (e.ajaxHooker_isStopped) return;
|
|
271
|
-
const onEvent = this.proxyEvents[
|
|
353
|
+
const onEvent = this.proxyEvents["on" + e.type];
|
|
272
354
|
onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
|
|
273
355
|
}
|
|
274
356
|
setRequestHeader(header, value) {
|
|
275
357
|
this.originalXhr.setRequestHeader(header, value);
|
|
276
358
|
if (!this.request) return;
|
|
277
359
|
const headers = this.request.headers;
|
|
278
|
-
headers[header] =
|
|
360
|
+
headers[header] =
|
|
361
|
+
header in headers ? `${headers[header]}, ${value}` : value;
|
|
279
362
|
}
|
|
280
363
|
addEventListener(...args) {
|
|
281
364
|
if (xhrAsyncEvents.includes(args[0])) {
|
|
@@ -293,18 +376,24 @@ const AjaxHooker = function () {
|
|
|
293
376
|
}
|
|
294
377
|
open(method, url, async = true, ...args) {
|
|
295
378
|
this.request = {
|
|
296
|
-
type:
|
|
379
|
+
type: "xhr",
|
|
297
380
|
url: url.toString(),
|
|
298
381
|
method: method.toUpperCase(),
|
|
299
382
|
abort: false,
|
|
300
383
|
headers: {},
|
|
301
384
|
data: null,
|
|
302
385
|
response: null,
|
|
303
|
-
async: !!async
|
|
386
|
+
async: !!async,
|
|
304
387
|
};
|
|
305
388
|
this.openArgs = args;
|
|
306
389
|
this.resThenable = new SyncThenable();
|
|
307
|
-
[
|
|
390
|
+
[
|
|
391
|
+
"responseURL",
|
|
392
|
+
"readyState",
|
|
393
|
+
"status",
|
|
394
|
+
"statusText",
|
|
395
|
+
...xhrResponses,
|
|
396
|
+
].forEach((key) => {
|
|
308
397
|
delete this.proxyProps[key];
|
|
309
398
|
});
|
|
310
399
|
return this.originalXhr.open(method, url, async, ...args);
|
|
@@ -317,17 +406,24 @@ const AjaxHooker = function () {
|
|
|
317
406
|
request.data = data;
|
|
318
407
|
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
319
408
|
if (request.abort) {
|
|
320
|
-
if (typeof request.response ===
|
|
409
|
+
if (typeof request.response === "function") {
|
|
321
410
|
Object.assign(ah.proxyProps, {
|
|
322
|
-
responseURL: {value: request.url},
|
|
323
|
-
readyState: {value: 4},
|
|
324
|
-
status: {value: 200},
|
|
325
|
-
statusText: {value:
|
|
411
|
+
responseURL: { value: request.url },
|
|
412
|
+
readyState: { value: 4 },
|
|
413
|
+
status: { value: 200 },
|
|
414
|
+
statusText: { value: "OK" },
|
|
326
415
|
});
|
|
327
|
-
xhrAsyncEvents.forEach(evt =>
|
|
416
|
+
xhrAsyncEvents.forEach((evt) =>
|
|
417
|
+
xhr.dispatchEvent(new Event(evt))
|
|
418
|
+
);
|
|
328
419
|
}
|
|
329
420
|
} else {
|
|
330
|
-
xhr.open(
|
|
421
|
+
xhr.open(
|
|
422
|
+
request.method,
|
|
423
|
+
request.url,
|
|
424
|
+
request.async,
|
|
425
|
+
...ah.openArgs
|
|
426
|
+
);
|
|
331
427
|
for (const header in request.headers) {
|
|
332
428
|
xhr.setRequestHeader(header, request.headers[header]);
|
|
333
429
|
}
|
|
@@ -338,79 +434,87 @@ const AjaxHooker = function () {
|
|
|
338
434
|
}
|
|
339
435
|
function fakeXHR() {
|
|
340
436
|
const xhr = new winAh.realXHR();
|
|
341
|
-
if (
|
|
437
|
+
if ("__ajaxHooker" in xhr)
|
|
438
|
+
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
342
439
|
xhr.__ajaxHooker = new XhrHooker(xhr);
|
|
343
440
|
return xhr.__ajaxHooker.proxyXhr;
|
|
344
441
|
}
|
|
345
442
|
fakeXHR.prototype = win.XMLHttpRequest.prototype;
|
|
346
|
-
Object.keys(win.XMLHttpRequest).forEach(
|
|
443
|
+
Object.keys(win.XMLHttpRequest).forEach(
|
|
444
|
+
(key) => (fakeXHR[key] = win.XMLHttpRequest[key])
|
|
445
|
+
);
|
|
347
446
|
function fakeFetch(url, options = {}) {
|
|
348
447
|
if (!url) return winAh.realFetch.call(win, url, options);
|
|
349
448
|
return new Promise(async (resolve, reject) => {
|
|
350
449
|
const init = {};
|
|
351
|
-
if (getType(url) ===
|
|
450
|
+
if (getType(url) === "[object Request]") {
|
|
352
451
|
for (const prop of fetchInitProps) init[prop] = url[prop];
|
|
353
452
|
if (url.body) init.body = await url.arrayBuffer();
|
|
354
453
|
url = url.url;
|
|
355
454
|
}
|
|
356
455
|
url = url.toString();
|
|
357
456
|
Object.assign(init, options);
|
|
358
|
-
init.method = init.method ||
|
|
457
|
+
init.method = init.method || "GET";
|
|
359
458
|
init.headers = init.headers || {};
|
|
360
459
|
const request = {
|
|
361
|
-
type:
|
|
460
|
+
type: "fetch",
|
|
362
461
|
url: url,
|
|
363
462
|
method: init.method.toUpperCase(),
|
|
364
463
|
abort: false,
|
|
365
464
|
headers: parseHeaders(init.headers),
|
|
366
465
|
data: init.body,
|
|
367
466
|
response: null,
|
|
368
|
-
async: true
|
|
467
|
+
async: true,
|
|
369
468
|
};
|
|
370
469
|
const req = new AHRequest(request);
|
|
371
470
|
await req.waitForRequestKeys();
|
|
372
471
|
if (request.abort) {
|
|
373
|
-
if (typeof request.response ===
|
|
472
|
+
if (typeof request.response === "function") {
|
|
374
473
|
const response = {
|
|
375
474
|
finalUrl: request.url,
|
|
376
475
|
status: 200,
|
|
377
|
-
responseHeaders: {}
|
|
476
|
+
responseHeaders: {},
|
|
378
477
|
};
|
|
379
478
|
await req.waitForResponseKeys(response);
|
|
380
|
-
const key = fetchResponses.find(k => k in response);
|
|
479
|
+
const key = fetchResponses.find((k) => k in response);
|
|
381
480
|
let val = response[key];
|
|
382
|
-
if (key ===
|
|
481
|
+
if (key === "json" && typeof val === "object") {
|
|
383
482
|
val = catchError(JSON.stringify.bind(JSON), val);
|
|
384
483
|
}
|
|
385
484
|
const res = new Response(val, {
|
|
386
485
|
status: 200,
|
|
387
|
-
statusText:
|
|
486
|
+
statusText: "OK",
|
|
388
487
|
});
|
|
389
|
-
defineProp(res,
|
|
390
|
-
defineProp(res,
|
|
488
|
+
defineProp(res, "type", () => "basic");
|
|
489
|
+
defineProp(res, "url", () => request.url);
|
|
391
490
|
resolve(res);
|
|
392
491
|
} else {
|
|
393
|
-
reject(new DOMException(
|
|
492
|
+
reject(new DOMException("aborted", "AbortError"));
|
|
394
493
|
}
|
|
395
494
|
return;
|
|
396
495
|
}
|
|
397
496
|
init.method = request.method;
|
|
398
497
|
init.headers = request.headers;
|
|
399
498
|
init.body = request.data;
|
|
400
|
-
winAh.realFetch.call(win, request.url, init).then(res => {
|
|
401
|
-
if (typeof request.response ===
|
|
499
|
+
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
500
|
+
if (typeof request.response === "function") {
|
|
402
501
|
const response = {
|
|
403
502
|
finalUrl: res.url,
|
|
404
503
|
status: res.status,
|
|
405
|
-
responseHeaders: parseHeaders(res.headers)
|
|
504
|
+
responseHeaders: parseHeaders(res.headers),
|
|
406
505
|
};
|
|
407
|
-
fetchResponses.forEach(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
506
|
+
fetchResponses.forEach(
|
|
507
|
+
(key) =>
|
|
508
|
+
(res[key] = function () {
|
|
509
|
+
if (key in response) return Promise.resolve(response[key]);
|
|
510
|
+
return resProto[key].call(this).then((val) => {
|
|
511
|
+
response[key] = val;
|
|
512
|
+
return req
|
|
513
|
+
.waitForResponseKeys(response)
|
|
514
|
+
.then(() => (key in response ? response[key] : val));
|
|
515
|
+
});
|
|
516
|
+
})
|
|
517
|
+
);
|
|
414
518
|
}
|
|
415
519
|
resolve(res);
|
|
416
520
|
}, reject);
|
|
@@ -423,38 +527,40 @@ const AjaxHooker = function () {
|
|
|
423
527
|
return res;
|
|
424
528
|
}
|
|
425
529
|
winAh = win.__ajaxHooker = winAh || {
|
|
426
|
-
version,
|
|
530
|
+
version,
|
|
531
|
+
fakeXHR,
|
|
532
|
+
fakeFetch,
|
|
533
|
+
fakeFetchClone,
|
|
427
534
|
realXHR: win.XMLHttpRequest,
|
|
428
535
|
realFetch: win.fetch,
|
|
429
536
|
realFetchClone: resProto.clone,
|
|
430
|
-
hookInsts: new Set()
|
|
537
|
+
hookInsts: new Set(),
|
|
431
538
|
};
|
|
432
|
-
if (winAh.version !== version)
|
|
539
|
+
if (winAh.version !== version)
|
|
540
|
+
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
433
541
|
win.XMLHttpRequest = winAh.fakeXHR;
|
|
434
542
|
win.fetch = winAh.fakeFetch;
|
|
435
543
|
resProto.clone = winAh.fakeFetchClone;
|
|
436
544
|
winAh.hookInsts.add(hookInst);
|
|
437
545
|
return {
|
|
438
|
-
hook: fn => hookInst.hookFns.push(fn),
|
|
439
|
-
filter: arr => {
|
|
546
|
+
hook: (fn) => hookInst.hookFns.push(fn),
|
|
547
|
+
filter: (arr) => {
|
|
440
548
|
if (Array.isArray(arr)) hookInst.filters = arr;
|
|
441
549
|
},
|
|
442
550
|
protect: () => {
|
|
443
|
-
readonly(win,
|
|
444
|
-
readonly(win,
|
|
445
|
-
readonly(resProto,
|
|
551
|
+
readonly(win, "XMLHttpRequest", winAh.fakeXHR);
|
|
552
|
+
readonly(win, "fetch", winAh.fakeFetch);
|
|
553
|
+
readonly(resProto, "clone", winAh.fakeFetchClone);
|
|
446
554
|
},
|
|
447
555
|
unhook: () => {
|
|
448
556
|
winAh.hookInsts.delete(hookInst);
|
|
449
557
|
if (!winAh.hookInsts.size) {
|
|
450
|
-
writable(win,
|
|
451
|
-
writable(win,
|
|
452
|
-
writable(resProto,
|
|
558
|
+
writable(win, "XMLHttpRequest", winAh.realXHR);
|
|
559
|
+
writable(win, "fetch", winAh.realFetch);
|
|
560
|
+
writable(resProto, "clone", winAh.realFetchClone);
|
|
453
561
|
delete win.__ajaxHooker;
|
|
454
562
|
}
|
|
455
|
-
}
|
|
563
|
+
},
|
|
456
564
|
};
|
|
457
|
-
}();
|
|
565
|
+
})();
|
|
458
566
|
};
|
|
459
|
-
|
|
460
|
-
export { AjaxHooker };
|