Javascript: переопределение XMLHttpRequest.open () - PullRequest
14 голосов
/ 15 октября 2011

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

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

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

Ответы [ 4 ]

38 голосов
/ 15 октября 2011

Вы не изменяете метод 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]
*/

Так что да, метод open нужно добавить в XMLHttpRequest prototype (window.XMLHttpRequest.prototype), а не XMLHttpRequest constructor (window.XMLHttpRequest)

3 голосов
/ 15 октября 2011

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

2 голосов
/ 15 октября 2011

Используйте взамен XMLHttpRequest.prototype.open.

1 голос
/ 07 июня 2019

Вот подход, который мне нравится использовать; имейте в виду, что освоение темных искусств обезьян 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 или веб-расширение, а также отменяет переопределение! ХА!

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

...