Патч обезьяны XMLHTTPRequest.onreadystatechange
Как бы про обезьяну залатать XMLHTTPRequest
"s onreadystatechange
функция. Я пытаюсь добавить функцию, которая будет вызываться при возвращении каждого ajax-запроса со страницы.
Я знаю, это звучит как ужасная идея, но случай использования довольно своеобразен. Я хочу использовать определенный SDK с консолью (jqconsole), но отображать состояние и результаты вызовов ajax внутри консоли без изменения внешнего SDK.
Я посмотрел на этот пост, в котором была отличная информация, но ничего о обезьяне, исправляющей обратный вызов, которая, кажется, превышает мои навыки JavaScript.
PS Не могу использовать jQuery, поскольку он поддерживает только вызовы ajax, сделанные из jQuery, а не из XMLHTTPRequests
прямо здесь.
3 ответа
К обезьянке-заплатке XMLHttpRequest
s, вам нужно знать, как обычно строится AJAX-запрос:
- Вызов конструктора
- Подготовка запроса (
setRequestHeader()
,open()
) - Отправка запроса (
.send
).
Универсальный патч
(function(xhr) {
function banana(xhrInstance) { // Example
console.log('Monkey RS: ' + xhrInstance.readyState);
}
// Capture request before any network activity occurs:
var send = xhr.send;
xhr.send = function(data) {
var rsc = this.onreadystatechange;
if (rsc) {
// "onreadystatechange" exists. Monkey-patch it
this.onreadystatechange = function() {
banana(this);
return rsc.apply(this, arguments);
};
}
return send.apply(this, arguments);
};
})(XMLHttpRequest.prototype);
Предыдущий предполагал, что onreadystatechange
был назначен на onreadystatechange
обработчик. Для простоты я не включил код для других событий, таких как onload
, Кроме того, я не учел события, добавленные с помощью addEventListener
,
Предыдущий патч работает для всех запросов. Но что, если вы хотите ограничить патч только конкретным запросом? Запрос с определенным URL или асинхронным флагом и конкретным телом запроса?
Условная обезьяна-патч
Пример: перехватывать все POST
запросы, тело запроса которых содержит "ТЕСТ"
(function(xhr) {
function banana(xhrInstance) { // Example
console.log('Monkey RS: ' + xhrInstance.readyState);
}
//
var open = xhr.open;
xhr.open = function(method, url, async) {
// Test if method is POST
if (/^POST$/i.test(method)) {
var send = this.send;
this.send = function(data) {
// Test if request body contains "TEST"
if (typeof data === 'string' && data.indexOf('TEST') >= 0) {
var rsc = this.onreadystatechange;
if (rsc) {
// Apply monkey-patch
this.onreadystatechange = function() {
banana(this);
return rsc.apply(this, arguments);
};
}
}
return send.apply(this, arguments);
};
}
return open.apply(this, arguments);
};
})(XMLHttpRequest.prototype);
Основные методы, используемые для прозрачного переписывания с использованием...
var original = xhr.method;
xhr.method = function(){
/*...*/;
return original.apply(this, arguments);
};
Мои примеры очень просты и могут быть расширены, чтобы удовлетворить ваши точные пожелания. Это зависит от вас, однако.
Вы можете учиться у Ajax-hook, написанного на китайском!
это расширенный js для включения Monkey patch XMLHTTPRequest
Предполагая, что вы можете игнорировать IE...
//Totally untested code, typed at the SO <textarea>... but the concept *should* work, let me know if it doesn't.
var OldXMLRequest = XMLHttpRequest;
// Create a new instance
function XMLHttpRequest() {
var ajax = new OldXMLRequest();
// save old function
var f = ajax.onreadystatechange;
ajax.onreadystatechange = function() {
console.log("Whatever!");
f(); // Call the old function
}
return ajax;
}