Вот подход, который мне нравится использовать; имейте в виду, что освоение темных искусств обезьян XHR - это своего рода искусство.
Заверните весь комплект и кабачок в IIFE. Итак, начните со следующего:
(function(open, send) {
//...overrides of the XHR open and send methods are now encapsulated within a closure
})(XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.send)
Любые методы могут быть переопределены с использованием этого общего подхода, но вышеприведенные скаффолдинги предоставляют вам способ переопределить (a.k.a monkey patch) оба метода open и send XMLHttpRequest; в одной аккуратной функции полезности. Обратите внимание на то, как «базовые» методы (из объекта-прототипа API) передаются в IIFE и назначаются для переменных «open» и «send» и безопасно ограничиваются функциональным блоком.
Теперь о смелости и о том, что является ключом к сохранению вашего патча обезьяны. Опять же, вот как я это делаю, и это работает.
Общая схема (все в пределах IIFE):
1) повторить метод и его аргументы (подпись, полностью, согласно спецификации / прототипу),
2) промах в моде и
3) примените ваши моды к свойству прототипа XHR, чтобы все запросы XHR проходили через ваш код.
Так, например, «open» будет выглядеть так:
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
xhrOpenRequestUrl = url; // update request url, closure variable
open.apply(this, arguments); // reset/reapply original open method
};
Не зацикливайтесь на xhrOpenRequestUrl = url; строка, этот код скопирован из примера, где мне понадобился URL для дальнейшей обработки. Ключ к выводу «open.apply», он скрепляет ваши настройки в методе XHR open, если вы не знакомы с методом «apply» или объектом «arguments», то сейчас самое время узнать, что они делают .
И аналогично для метода "send" ...
XMLHttpRequest.prototype.send = function(data) {
//...what ever code you need, i.e. capture response, etc.
if (this.readyState == 4 && this.status >= 200 && this.status < 300) {
xhrSendResponseUrl = this.responseURL;
responseData = this.data; // now you have the data, JSON or whatever, hehehe!
}
send.apply(this, arguments); // reset/reapply original send method
}
Опять же, «применить» имеет решающее значение, и это должно быть сделано после всех ваших переопределений. Так что теперь все вместе ...
(function(open, send) {
// Closure/state var's
var xhrOpenRequestUrl; // captured in open override/monkey patch
var xhrSendResponseUrl; // captured in send override/monkey patch
var responseData; // captured in send override/monkey patch
//...overrides of the XHR open and send methods are now encapsulated within a closure
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
xhrOpenRequestUrl = url; // update request url, closure variable
open.apply(this, arguments); // reset/reapply original open method
};
XMLHttpRequest.prototype.send = function(data) {
//...what ever code you need, i.e. capture response, etc.
if (this.readyState == 4 && this.status >= 200 && this.status < 300) {
xhrSendResponseUrl = this.responseURL;
responseData = this.data; // now you have the data, JSON or whatever, hehehe!
}
send.apply(this, arguments); // reset/reapply original send method
}
})(XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.send)
Да, и последнее, ваш патч обезьяны, в свою очередь, может быть патчирован обезьяной! Чтобы минимизировать эту возможность, код IIFE должен идти после всех остальных JS на странице. По крайней мере, все JS, которые могут быть обезьянами с XHR, но перед любыми вызовами AJAX, на которые вы, возможно, нацеливаетесь. Кроме того, аналогичным образом, патч XHR-обезьяны может быть введен через Chrome или веб-расширение, а также отменяет переопределение! ХА!
Надеюсь, это поможет!