JavaScript обнаруживает событие AJAX

Итак, в основном я хочу разместить на странице немного javascript, который каким-то образом присоединяет некоторый глобальный слушатель событий, который может обнаруживать и делать что-то, если сделан запрос ajax (без непосредственного вызова из вызова), независимо от того, как работает ajax звонок сделан.

Я понял, как это сделать с помощью jquery - если запрос ajax выполняется с помощью jquery. Вот пример кода для этого:

$.post(
  // requested script
  'someScript.php', 
  // data to send
  {
    'foo' : 'bar',
    'a' : 'b'
  },
  // receive response
  function(response){
    // do something
  }
); // .post

// global event listener    
$(document).ajaxSend(
  function(event,request,settings){
    alert(settings.url); // output: "someScript.php"
    alert(settings.data); // output: "foo=bar&a=b"
  }
);

С этим кодом, независимо от того, где / как я вызываю $.post (..), сработает глобальный прослушиватель событий. Это также работает, если я использую $.get или $.ajax (любые методы jquery ajax), независимо от того, как / когда я его вызываю (прикрепляется как onclick, при загрузке страницы, как угодно).

Тем не менее, я хочу иметь возможность расширять этот слушатель для запуска независимо от того, какой js-фреймворк используется, или даже если никакой фреймворк не используется. Так, например, если бы у меня также был на странице следующий код (общий код ajax от w3schools):

function loadXMLDoc()
{
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","test.txt",true);
xmlhttp.send();
}

И затем, по какой-то случайной ссылке, с помощью функции onclick вызывается эта функция, мой глобальный прослушиватель ajax-событий должен иметь возможность обнаруживать этот запрос. Ну, я добавил этот код на свою страницу и прикрепил его к щелчку произвольной ссылки (да, сам код работает), но приведенный выше код jquery "слушатель глобального события" не смог обнаружить этот вызов.

Я сделал еще несколько копаний и знаю, что в принципе могу сохранить объект во временном объекте и перезаписать текущий объект объектом-оболочкой, который вызовет указанную функцию, а затем вызовет временную функцию, но для этого нужно знать заранее время создания / использования исходного объекта. Но я не всегда буду знать, что раньше...

Итак... это возможно? Есть ли какой-нибудь способ обнаружить ajax-запрос get / post, независимо от того, был ли он сделан с универсальным объектом или из фреймворка xyz? Или мне просто нужно будет создать дублирующий код для обработки каждой среды, а также заранее знать, какие объекты / объекты ajax создаются / используются?

редактировать:

Я забыл упомянуть, что недостаточно обнаружить запрос. Мне также нужно захватить данные, отправляемые в запросе. Ссылка, приведенная в комментариях ниже, поможет выяснить, был ли сделан запрос "а", но не получить отправленные данные. ps - ответ, приведенный в ссылке ниже, не очень понятен, по крайней мере, для меня в любом случае.

3 ответа

Решение

Хорошо, это то, что я придумал до сих пор:

<script type='text/javascript'>
var s_ajaxListener = new Object();
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
  // this.method :the ajax method used
  // this.url    :the url of the requested script (including query string, if any) (urlencoded) 
  // this.data   :the data sent, if any ex: foo=bar&a=b (urlencoded)
}

XMLHttpRequest.prototype.open = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempOpen.apply(this, arguments);
  s_ajaxListener.method = a;  
  s_ajaxListener.url = b;
  if (a.toLowerCase() == 'get') {
    s_ajaxListener.data = b.split('?');
    s_ajaxListener.data = s_ajaxListener.data[1];
  }
}

XMLHttpRequest.prototype.send = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempSend.apply(this, arguments);
  if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
  s_ajaxListener.callback();
}
</script>

НАПРАВЛЕНИЯ:

Просто скопируйте это на свою страницу или включите в файл.js или что-то еще. Это создаст объект с именем s_ajaxListener. Всякий раз, когда выполняется запрос AJAX GET или POST, вызывается s_ajaxListener.callback(), и доступны следующие свойства:

s_ajaxListener.method: используемый метод ajax. Это должно быть либо GET, либо POST. ПРИМЕЧАНИЕ: значение не всегда может быть в верхнем регистре, это зависит от того, как был закодирован конкретный запрос. Я обсуждаю целесообразность автоматического ввода заглавных букв или предоставления чего-то другого toLowerCase() для сравнения без учета регистра.

s_ajaxListener.url: URL запрошенного скрипта (включая строку запроса, если есть) (urlencoded). Я заметил, в зависимости от того, как данные отправляются и из какого браузера / фреймворка, например, это значение может в конечном итоге быть " " или "+" или "%20". Я обсуждаю мудрость расшифровки здесь или оставляю это другому.

s_ajaxListener.data: отправленные данные, если таковые имеются, например: foo=bar&a=b (та же "проблема", что и.url, с кодировкой URL)

ЗАМЕТКИ:

В настоящее время это не совместимо с IE6. это решение не совсем достаточно для меня, так как я хочу, чтобы оно было совместимо с IE6. Но поскольку многие другие не заботятся о IE6, я решил опубликовать свое решение в его текущем состоянии, так как оно должно работать для вас, если вас не волнует IE6.

Я проверил это в (по состоянию на эту дату): текущее Safari, текущий Chrome, текущий FireFox, IE8, IE8 (IE7 совместимый). В настоящее время он не работает с IE6, потому что IE6 использует объект ActiveX, в то время как практически все остальное использует XMLHttpRequest.

Прямо сейчас я не имею ни малейшего понятия, как, ну в основном прототип / расширение / перегрузка (?) ActiveXObject("Microsoft.XMLHTTP"). Это то, что я сейчас исследую... кто-нибудь знает это случайно?

В каждом из браузеров, которые я тестировал выше, это работает с AJAX-запросами от универсального объекта, а также от сред jquery и prototype. Я знаю, что есть другие структуры, но IMO, эти 2 являются основными. Я мог бы, возможно, QA MooTools, но кроме этого, я в порядке только с тестированием тех.

Если кто-то захочет внести свой вклад путем тестирования и публикации результатов о других браузерах и / или фреймворках, это будет оценено:)

Для совместимости с IE 6, как насчет:

<script type='text/javascript'>
  var s_ajaxListener = new Object();

  // Added for IE support
  if (typeof XMLHttpRequest === "undefined") {
    XMLHttpRequest = function () {
      try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
      catch (e) {}
      try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
      catch (e) {}
      try { return new ActiveXObject("Microsoft.XMLHTTP"); }
      catch (e) {}
      throw new Error("This browser does not support XMLHttpRequest.");
    };
  }

  s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
  s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
  s_ajaxListener.callback = function () {
    // this.method :the ajax method used
    // this.url    :the url of the requested script (including query string, if any) (urlencoded) 
    // this.data   :the data sent, if any ex: foo=bar&a=b (urlencoded)
  }

  XMLHttpRequest.prototype.open = function(a,b) {
    if (!a) var a='';
    if (!b) var b='';
    s_ajaxListener.tempOpen.apply(this, arguments);
    s_ajaxListener.method = a;  
    s_ajaxListener.url = b;
    if (a.toLowerCase() == 'get') {
      s_ajaxListener.data = b.split('?');
      s_ajaxListener.data = s_ajaxListener.data[1];
    }
  }

  XMLHttpRequest.prototype.send = function(a,b) {
    if (!a) var a='';
    if (!b) var b='';
    s_ajaxListener.tempSend.apply(this, arguments);
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
    s_ajaxListener.callback();
  }
</script>

Имея необходимость прослушивать события AJAX с помощью других скриптов (либо XHR, либо fetch) и вдохновленный этим сообщением SO, я создал небольшую утилиту, которая довольно универсальна, AjaxListener.js на GitHub (примечание: IE < 7 НЕ поддерживается ).

Основное использование:

      function mylistener(req, res)
{
    // API is either 'xhr' or 'fetch'
    console.log('REQUEST', 'API', req.getAPI(), 'Method', req.getMethod(), 'URL', req.getURL(), 'Headers', req.getHeaders(), 'Body', req.getBody());
    console.log('RESPONSE', 'API', res.getAPI(), 'Status', res.getStatus(), 'URL', res.getURL(), 'Headers', res.getHeaders(), 'Body', res.getBody());
}

AjaxListener.install().onRequest(mylistener);

//AjaxListener.onRequest(mylistener, false); // unlisten

//AjaxListener.uninstall(); // uninstall

Надеюсь, это полезно.

Другие вопросы по тегам