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