Подтвердить что ты не робот

Javascript: переопределение XMLHttpRequest.open()

Как я могу переопределить метод XMLHttpRequest.open(), а затем уловить и изменить его аргументы?

Я уже пробовал прокси-метод, но он не работал, хотя удалял открытый избыточный код при вызове XMLHttpRequest():

(function() {
    var proxied = window.XMLHttpRequest.open;
    window.XMLHttpRequest.open = function() {
        $('.log').html(arguments[0]);
        return proxied.apply(this, arguments);
    };
})();
4b9b3361

Ответ 1

Вы не изменяете метод open, унаследованный XMLHttpRequest objects, а просто добавляете метод к XMLHttpRequest constructor, который на самом деле никогда не используется.

Я пробовал этот код в facebook, и мне удалось поймать запросы:

(function() {
    var proxied = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function() {
        console.log( arguments );
        return proxied.apply(this, [].slice.call(arguments));
    };
})();

/*
    ["POST", "/ajax/chat/buddy_list.php?__a=1", true]
    ["POST", "/ajax/apps/usage_update.php?__a=1", true]
    ["POST", "/ajax/chat/buddy_list.php?__a=1", true]
    ["POST", "/ajax/canvas_ticker.php?__a=1", true]
    ["POST", "/ajax/canvas_ticker.php?__a=1", true]
    ["POST", "/ajax/chat/buddy_list.php?__a=1", true]
*/

Итак, открытый метод должен быть добавлен в XMLHttpRequest prototype (window.XMLHttpRequest.prototype) не XMLHttpRequest constructor (window.XMLHttpRequest)

Ответ 2

Я бы предложил xmlhttprequest проект в коде google. Это довольно хороший пример правильного переопределения объекта XMLHttpRequest. Источник можно увидеть здесь.

Ответ 3

Вместо этого используйте XMLHttpRequest.prototype.open.

Ответ 4

Вот подход, который мне нравится использовать; имейте в виду, освоение темного искусства 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)

Любые методы могут быть переопределены с использованием этого общего подхода, но приведенные выше скаффолдинги предоставляют вам способ переопределить (также известный как патч обезьяны) как методы 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", то сейчас самое время узнать, что они делают,

И аналогично для метода "отправить"...

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 или веб-расширение, а также отменяет переопределение! ХА!

Надеюсь, это поможет!