JavaScript erkennt ein AJAX-Ereignis

78

Okay, im Grunde möchte ich ein bisschen Javascript auf einer Seite haben, die irgendwie eine Art globalen Ereignis-Listener anfügt, der etwas erkennen und tun kann, wenn eine Ajax-Anfrage gestellt wird (ohne sie direkt vom Aufruf aus aufzurufen), unabhängig davon, wie der Ajax ist Anruf wird getätigt.

Ich habe herausgefunden, wie man das mit jquery macht - wenn die Ajax-Anfrage von jquery gemacht wird. Hier ist ein Beispielcode dafür:

$.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"
  }
);

Mit diesem Code wird unabhängig davon, wo / wie ich $ .post (..) aufrufe, der globale Ereignis-Listener ausgelöst. Es funktioniert auch, wenn ich $ .get oder $ .ajax (beliebige jquery ajax-Methoden) verwende, unabhängig davon, wie / wann ich es aufrufe (als Onclick angehängt, beim Laden der Seite, was auch immer).

Ich möchte diesen Listener jedoch erweitern können, um ihn auszulösen, unabhängig davon, welches js-Framework verwendet wird oder auch wenn kein Framework verwendet wird. Wenn ich zum Beispiel auch auf einer Seite den folgenden Code haben würde (generischer Ajax-Code von 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();
}

Und dann habe ich über einen zufälligen Link einen On-Click-Aufruf dieser Funktion. Mein globaler Ajax-Ereignis-Listener sollte in der Lage sein, diese Anforderung ebenfalls zu erkennen. Nun, ich habe diesen Code zu meiner Seite hinzugefügt und ihn an den Klick eines zufälligen Links angehängt (ja, der Code selbst funktioniert), aber der obige jquery-Code "Global Event Listener" konnte diesen Aufruf nicht erkennen.

Ich habe noch etwas gegraben und weiß, dass ich das Objekt im Grunde genommen in einem temporären Objekt speichern und das aktuelle Objekt mit einem "Wrapper" -Objekt überschreiben kann, das eine bestimmte Funktion aufruft und dann die temporäre Funktion aufruft, aber dies erfordert, dass ich es vorher weiß Zeit, zu der das ursprüngliche Objekt erstellt / verwendet wird. Aber das werde ich nicht immer im Voraus wissen ...

Also ... ist das möglich? Gibt es eine Möglichkeit zu erkennen, dass eine Ajax-Get / Post-Anfrage gestellt wurde, unabhängig davon, ob sie mit einem generischen Objekt oder aus einem xyz-Framework durchgeführt wurde? Oder muss ich nur doppelten Code erstellen, um jedes Framework zu handhaben, und im Voraus wissen, welche Ajax-Objekte erstellt / verwendet werden?

bearbeiten:

Ich habe vergessen zu erwähnen, dass es nicht ausreicht, zu erkennen, dass eine Anfrage aufgetreten ist. Ich muss auch die Daten erfassen, die in der Anfrage gesendet werden. Über den in den Kommentaren unten angegebenen Link können Sie herausfinden, ob eine "Anfrage" gestellt wurde, die Daten jedoch nicht gesendet werden. ps - die Antwort im Link unten ist nicht sehr klar, zumindest für mich.

Wachsmalstift gewalttätig
quelle
Danke für den Link! Diese Frage ist nicht ganz so, weil ich auch in der Lage sein musste, die in der Anfrage gesendeten Daten zu erfassen (die ich vermutlich nicht aufgenommen habe; bearbeitet in). Es hat mich jedoch auf den richtigen Weg gebracht und ich denke, ich habe eine Lösung gefunden, die veröffentlicht wird, wenn der Test abgeschlossen ist. Vielen Dank!
Crayon Violent
Ich denke, was Sie suchen, ist in dieser Frage über die Manipulation des Prototyps, aber auf eine bessere Weise stackoverflow.com/q/20689481/3462483
doz87

Antworten:

108

Okay, das habe ich mir bisher ausgedacht:

<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>

RICHTUNGEN:

C / p dies einfach auf Ihre Seite oder fügen Sie es in eine .js-Datei oder was auch immer. Dadurch wird ein Objekt mit dem Namen s_ajaxListener erstellt. Immer wenn eine AJAX GET- oder POST-Anforderung gestellt wird, wird s_ajaxListener.callback () aufgerufen, und die folgenden Eigenschaften sind verfügbar:

s_ajaxListener.method : Die verwendete Ajax- Methode. Dies sollte entweder GET oder POST sein. HINWEIS: Der Wert ist möglicherweise nicht immer in Großbuchstaben geschrieben. Dies hängt davon ab, wie die spezifische Anforderung codiert wurde. Ich diskutiere die Weisheit, es automatisch in Großbuchstaben zu schreiben oder es etwas anderem zu überlassen, um es dem Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung zu unterwerfen.

s_ajaxListener.url : Die URL des angeforderten Skripts (einschließlich etwaiger Abfragezeichenfolge) (urlencodiert). Ich habe festgestellt, dass dieser Wert je nachdem, wie die Daten gesendet werden und von welchem ​​Browser / Framework, beispielsweise "" oder "+" oder "% 20" lautet. Ich diskutiere die Weisheit, es hier zu entschlüsseln oder es etwas anderem zu überlassen.

s_ajaxListener.data : die gesendeten Daten, falls vorhanden ex: foo = bar & a = b (dasselbe 'Problem' wie .url, wenn es url-codiert ist)

ANMERKUNGEN:

Wie es aussieht, ist dies nicht IE6 kompatibel . Diese Lösung ist für mich nicht gut genug, da ich möchte, dass sie IE6-kompatibel ist. Da sich viele andere Leute nicht für IE6 interessieren, habe ich beschlossen, meine Lösung in ihrem aktuellen Zustand zu veröffentlichen, da sie für Sie funktionieren sollte, wenn Sie sich nicht für IE6 interessieren.

Ich habe dies getestet in (ab diesem Datum): Aktuelle Safari, Aktuelles Chrome, Aktuelles FireFox, IE8, IE8 (IE7-kompatibel). Derzeit funktioniert es nicht mit IE6, da IE6 ein ActiveX-Objekt verwendet, während praktisch alles andere XMLHttpRequest verwendet.

Im Moment habe ich keine Ahnung, wie man das macht, im Grunde genommen Prototyp / Erweitern / Überladen (?) ActiveXObject ("Microsoft.XMLHTTP"). Dies ist, was ich gerade erforsche ... weiß jemand spontan?

Unter jedem der oben getesteten Browser funktioniert dies mit AJAX-Anforderungen von einem generischen Objekt sowie von den Frameworks jquery und prototype. Ich weiß, dass es andere Frameworks gibt, aber IMO sind diese beiden die wichtigsten. Ich könnte möglicherweise QA MooTools, aber ansonsten kann ich nur diese testen.

Wenn jemand einen Beitrag leisten möchte, indem er Ergebnisse über andere Browser und / oder Frameworks testet und veröffentlicht, wäre er dankbar :)

Wachsmalstift gewalttätig
quelle
1
Sie können eine Wrapper-Funktion für IE6 definieren, wie es Sarissa tut. Schauen Sie sich XMLHttpRequest neu an, um zu sehen, wie dies getan werden kann (ich habe jetzt keine Zeit). Sie können ein ActiveX-Objekt nicht erweitern , aber Sie können Ihre eigene Wrapper-Funktion erweitern, die einfach die erforderlichen Eigenschaften emuliert. Ich denke, die meisten Bibliotheken testen auf das Vorhandensein von window.XMLHttpRequestund Ihr Wrapper-Objekt wird erkannt.
Marcel Korpel
Beachten Sie auch, dass IE8 im IE7-Kompatibilitätsmodus ≠ IE7 ist. Ich vermute, dass das XMLHttpRequestObjekt eines der Dinge ist, die sich unterscheiden: In IE7 scheint es lediglich eine Wrapper-Funktion über eine ActiveX-Komponente zu sein, während es in IE8 als 'echtes' XHR-Objekt implementiert sein kann.
Marcel Korpel
1
Funktioniert derzeit nicht in FireFox. XMLHttpRequest.open.apply Fehler aus
HMR
Funktioniert immer noch hervorragend, wird aber aus irgendeinem Grund XMLHttpRequest.sendbei jedem Klick in Chrome aufgerufen und der Rückruf wird bei jedem Klick ausgeführt
Petr Gazarov
@PetrGazarov interessant .. Ich frage mich, ob dies ein Nebeneffekt des Vorabrufens ist?
Crayon Violent
5

Wie wäre es mit der IE 6-Kompatibilität:

<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>
Sébastien Brodeur
quelle
6
Ja, das ist so ziemlich das, was ich damals gemacht habe. Aber IE6 ist etwas, das niemand mehr unterstützen sollte, zumal Microsoft es ab April 2014 eingestellt hat (durch die Erweiterung, XP nicht zu unterstützen)
Crayon Violent