2.1 Funktionen des Ajax-Kernels

Code des Ajax-Kernels

Für unsere einfachen Beispiele und für viele Anwendungsfälle in der Praxis genügt der nachfolgend vorgestellte Ajax-Kernel.

Eine Möglichkeit besteht darin, den nachfolgenden Code in einer eigenen JavaScript-Datei zu speichern – nennen wir sie ajax.js:

// --------------- AJAX-Initialisierung
var ajax = false;
if(window.XMLHttpRequest)  // Mozilla, Safari,...
   ajax = new XMLHttpRequest();
else if(window.ActiveXObject) { // IE
   try {
      ajax = new ActiveXObject("Msxml2.XMLHTTP");
   }
   catch (e) {
      try {
         ajax = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {}
   }
}
// Ende AJAX-Initialisierung
 
// ------------------------------------- 
function do_http_get_request(type, url, output_id) {   
   if(!ajax)
          return false;
   ajax.onreadystatechange = function() {
      if(ajax.readyState == 4) {
         if(ajax.status == 200) {
                        if(type == "text")
               handle_text_response(ajax.responseText, output_id);
                         else if(type == "xml")
               handle_xml_response(ajax.responseXML, output_id);
                 }
             else
                return false;
      }
          else
             return false;
   } 
   ajax.open('GET', url, true);
   ajax.send(null);
}
 
// ------------------------------------- 
function do_http_post_request(type, url, post_field_ids, output_id) {   
   if(!ajax)
          return false;
   var post_field_array = post_field_ids.split("+");
   post_field_str = "";
   for(i = 0; i < post_field_array.length; i++) {
          post_field_id = post_field_array[i];
          post_field_value = document.getElementById(post_field_id).value;
      post_field_str += post_field_id + "=" +  
                     encodeURIComponent(post_field_value) + "&";
   }
   if(post_field_str.length > 1)
      post_field_str = post_field_str.substr(0, post_field_str.length - 1);
   ajax.onreadystatechange = function() {
      if(ajax.readyState == 4) {
         if(ajax.status == 200) {
                        if(type == "text")
               handle_text_response(ajax.responseText, output_id);
                        else if(type == "xml")
               handle_xml_response(ajax.responseXML, output_id);
                 }
             else
                return false;
      }
          else
             return false;
   } 
   ajax.open('POST', url, true);
   ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
   ajax.send(post_field_str);
}
 
// ------------------------------------- 
function handle_text_response(content, output_id) {
   if(!document.getElementById)
      return false;
   if(!document.getElementById(output_id))
          return false;
   document.getElementById(output_id).innerHTML = content;
} 
 
// ------------------------------------- 
function handle_xml_response(content, output_id) {
   if(!document.getElementById)
      return false;
   if(!document.getElementById(output_id))
          return false;
   if(xml_response_handler)
          xml_response_handler(ajax.responseXML, output_id);
}

Um die Funktionsweise des Ajax-Kernels zu verstehen, ist es wichtig, Details aus dem Kernel-Code nachzuvollziehen.
Im ersten Teil des Scripts ist der Code für die Initialisierung des XML-HTTP-Objekts notiert. Diesen Code kennen wir bereits. Mit einer Browserweiche werden die bekannten Implementierungsvarianten des XML-HTTP-Objekts erkannt. In der Variablen ajax wird das erzeugte XML-HTTP-Objekt gespeichert. Da der Code zur Initialisierung des Objekts außerhalb jeder Funktion notiert ist, wird er sofort beim Einlesen der ajax.js ausgeführt. Das XML-HTTP-Objekt kann steht damit automatisch zur Verfügung.

Der Rest des Kernels besteht aus folgenden Funktionen:

  • do_http_get_request(type, url, output_id):
    Diese Funktion setzt einen HTTP-Request mit der Übertragungsmethode GET ab. Beim Parameter type erwartet die Funktion einen der beiden Werte "text" oder "xml". Bei "text" wird die Serverantwort als gewöhnliche Zeichenkette interpretiert, und bei "xml" als DOM-Objekt. Im Parameter url wird der Funktion die URL-Adresse übergeben, die im HTTP-Request angefordert werden soll (in der Regel ein serverseitiges Script). Der Parameter output_id schließlich erwartet den id-Namen eines HTML-Elements der aktuellen Webseite. Die Funktion sorgt dafür, dass die Nutzdaten der Serverantwort in diesem HTML-Element platziert werden.
  • do_http_post_request(type, url, post_field_ids, output_id):
    Diese Funktion setzt einen HTTP-Request mit der Übertragungsmethode POST ab. Die Parameter sind die gleichen wie bei do_http_get_request(), erweitert um einen dritten Parameter namens post_field_ids. In diesem Parameter erwartet die Funktion id-Namen von HTML-Formulareingabefeldern, deren aktueller Inhalt via POST-Methode gesendet werden soll. Die id-Namen müssen durch Pluszeichen getrennt sein, also z.B. vorname+zuname+mail+telefon+thema+text.
  • handle_text_response(content, output_id):
    Diese Funktion wird von do_http_get_request() und do_http_post_request() intern aufgerufen, wenn der type-Parameter den Wert "text" hat. Sie sorgt für die Ausgabe der empfangenen Serverantwort im Inhalt des gewünschten HTML-Elements. Im Parameter content erwartet sie die Zeichenkette der auszugebenden Daten.
  • handle_xml_response(content, output_id):
    Diese Funktion wird von do_http_get_request() und do_http_post_request() intern aufgerufen, wenn der type-Parameter den Wert "xml" hat. Im Parameter content erwartet sie ein DOM-Objekt mit XML-Daten. Die Funktion prüft, ob es eine globale Variable mit Namen xml_response_handler gibt, in der eine Funktion gespeichert sein sollte, die das erhaltene XML-Format verarbeiten und in eine geeignete HTML-Struktur übersetzen kann.

Ablauf eines GET-Requests

Innerhalb unseres zuvor vorgestellten Ajax-Kernels nimmt die Funktion do_http_get_request() die Aufgabe wahr, einen HTTP-GET-Request zu senden und die Antwort des Webservers zu verarbeiten. Betrachten wir deshalb den Code dieser Funktion genauer.

Zunächst wird mit if(!ajax) geprüft, ob das globale XML-HTTP-Objekt mit Namen ajax eventuell nicht initialisiert werden konnte. Ist das der Fall, wird sofort abgebrochen.

In der nächsten Code-Zeile ist ajax.onreadystatechange = function() notiert. Dabei sieht onreadystatechange aus wie eine Eigenschaft des XML-HTTP-Objekts. Das Präfix on… signalisiert jedoch, dass es sich um einen Event-Handler handelt, also um ein Ereignis, bei dessen Eintreffen etwas Bestimmtes geschehen soll. Deshalb wird dieser Eigenschaft auch kein einfacher Wert wie eine Zahl oder eine Zeichenkette zugewiesen, sondern eine sogenannte anonyme Funktion (eine Funktion ohne Namen), die bei Eintreffen des Ereignisses ausgeführt wird.

Der Code innerhalb der anonymen Funktion lautet:

      if(ajax.readyState == 4) {
         if(ajax.status == 200) {
                        if(type == "text")
               handle_text_response(ajax.responseText, output_id);
                         else if(type == "xml")
               handle_xml_response(ajax.responseXML, output_id);
                 }
             else
                return false;
      }
          else
             return false;

readyState ist eine »echte« Eigenschaft des XML-HTTP-Objekts. In der Eigenschaft wird in Form eines Integer-Werts gespeichert, in welcher Phase sich eine aktuelle, vom XML-HTTP-Objekt gestartete HTTP-Kommunikation befindet. Mögliche Werte sind 0 bis 4. Eine vollständige HTTP-Kommunikation durchläuft nacheinander alle fünf Werte:

0 ist einfach der Anfangswert.
1 bedeutet, dass die HTTP-Verbindung zum Webserver erfolgreich zustande kam.
2 bedeutet, dass der HTTP-Request vollständig übertragen wurde.
3 bedeutet, dass die HTTP-Header der Server-Antwort empfangen wurden.
4 bedeutet, dass die Server-Antwort komplett übertragen wurde.

Der Event-Handler onreadystatechange bewirkt, dass bei jeder Änderung des Werts von readyState die Prozedur, die onreadystatechange zugewiesen ist, erneut ausgeführt wird. Innerhalb der zugewiesenen anonymen Funktion könnten wir also auf jede genannte Phase der HTTP-Kommunikation mit Script-Code reagieren. Im Beispiel reagieren wir jedoch nur auf die letzte Phase, nämlich mit if(httpRequest.readyState == 4). Die übrigen Phasen werden durch durch else return false ignoriert.

Wenn readyState den Wert 4 hat, ist also die HTTP-Kommunikation abgeschlossen und der Webserver hat seine Antwort auf eine Anfrage gesendet. Um die Antwort auszuwerten, ist es zweckmäßig, zunächst den HTTP-Statuscode der Server-Antwort auszulesen. Dieser ist in der Eigenschaft status des XML-HTTP-Objekts gespeichert. In unserem Beispiel erwarten wir für den »Gutfall« den HTTP-Status-Code 200. Dieser Code bedeutet, dass der Server den HTTP-Request erfolgreich bearbeiten konnte und die angeforderten Daten senden konnte.

Auf den HTTP-Status-Code 200 reagieren wir mit einem Aufruf entweder der Funktion handle_text_response() oder handle_xml_response(), abhängig davon, ob der type-Parameter den Wert "text" oder "xml" hat. Beiden Funktionen werden im ersten Parameter die vom Webserver erhaltenen Nutzdaten übergeben. Empfangende Textdaten werden in der Eigenschaft responseText des XML-HTTP-Objekts gespeichert, DOM-Objektdaten eines XML-Dokuments dagegen in der Eigenschaft responseXML. Wenn also beispielsweise ein über Ajax aufgerufenes PHP-Script auf dem Server HTML-Code generiert und zurückgibt, ist in der Objekteigenschaft responseText dieser HTML-Code als Zeichenkette enthalten.

Die beiden letzten Anweisungen der Funktion do_http_get_request() sind einigermaßen verständlich. Mit ajax.open('GET', url, true); wird die Methode open() des XML-HTTP-Objekts aufgerufen. Diese Methode setzt einen HTTP-Request an den Server ab. Als erster Parameter wird die Request-Methode angegeben. In unserem Fall ist das die GET-Methode. Der zweite Parameter übergibt die URL-Adresse, an die der HTTP-Request gehen soll. Der dritte Parameter ist ein true-false-Wert. Wenn auf true gesetzt (was auch die Default-Einstellung ist), wird die JavaScript-Funktion weiter ausgeführt, auch wenn noch keine Server-Antwort vorliegt (asynchrone Verarbeitung – daher das »A« in »Ajax«!). Wenn auf false gesetzt, wartet JavaScript dagegem mit der Ausführung der weiteren Anweisungen so lange, bis die Server-Antwort vorliegt (synchrone Verarbeitung). Die Funktion ist bei asynchroner Verarbeitung eigentlich längst beendet, wenn die Antwortdaten vom Webserver eintreffen. Um sie dennoch abzufangen, haben wir zuvor die Ereignisbehandlung für onreadystatechange definiert.
Mit ajax.send(null) wird dem Server mitgeteilt, dass außer dem GET-Request keine weiteren Daten an den Server gesendet werden.

Ablauf eines POST-Requests

Innerhalb unseres Ajax-Kernels ist die Funktion do_http_post_request() für HTTP-POST-Requests zuständig. Die Funktion hat den gleichen Aufbau wie die Funktion do_http_post_request() für GET-Requests. Beschränken wir uns also auf die Unterschiede.

Im Parameter post_field_ids werden wie weiter oben schon beschrieben id-Namen jerjenigen Felder übergeben, deren Inhalt via POST an den Webserver übertragen werden soll. Der Parameter enthält bei der Übergabe typischerweise einen Wert wie vorname+zuname+mail+telefon+thema+text. Aus diesen Feldern und ihren Inhalten muss do_http_post_request() zunächst einen Parameterstring erzeugen, der genauso aussieht wie ein typischer GET-Parameterstring:

Dazu werden zunächst durch Aufruf der Methode split() die id-Feldnamen in einen Array namens post_field_array übertragen:

var post_field_array = post_field_ids.split("+");

Der so erzeugte Array wird anschließend in einer for-Schleife abgearbeitet. Dabei wird die Variable post_field_str nach und nach mit Inhalt gefüllt:

   for(i = 0; i < post_field_array.length; i++) {
          post_field_id = post_field_array[i];
          post_field_value = document.getElementById(post_field_id).value;
      post_field_str += post_field_id + "=" +  
                     encodeURIComponent(post_field_value) + "&";
   }

Ermittelt wird in jedem Schleifendurchlauf der aktuelle id-Elementname eines Formularfeldes. Dieser wird in post_field_id gespeichert. Dann greift document.getElementById(post_field_id).value auf den aktuellen Wert des Formularfeldes zu und speichert ihn in post_field_value. Zuletzt wird post_field_str um ein name-value-Paar erweitert. Auf den Feldwert wird die JavaScript-Funktion encodeURIComponent() angewendet. Dadurch wird erreicht, dass der Parameterstring die Vorgaben des HTTP-Übertragungsformats www-form-url-encoded erfüllt.

Unterhalb der for-Schleife wird das letzte Parametertrennzeichen »&« entfernt, das beim Zusammenbasteln von post_field_str entstanden ist:

   if(post_field_str.length > 1)
      post_field_str = post_field_str.substr(0, post_field_str.length - 1);

Die Behandlung von onreadystatechange und readyState ist in do_http_post_request() die gleiche wie in do_http_get_request(). Unterschiedlich sind erst wieder die letzten Zeilen der Funktion:

   ajax.open('POST', url, true);
   ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
   ajax.send(post_field_str);

Beim Aufruf der open()-Methode des XML-HTTP-Objekts wird als erster Parameter die gewünschte Übertragungsmethode 'POST' übergeben. Außerdem senden wir im Fall der POST-Datenübertragung im HTTP-Request einen zusätzlichen HTTP-Header. Dazu bietet das XML-HTTP-Objekt die Methode setRequestHeader() an. Wir definieren mit application/x-www-form-urlencoded den MimeType (Content-Type) der übertragenen Daten. Abschließend wird der HTTP-Request durch Aufruf der send()-Methode abgesetzt. Anders als bei do_http_get_request() wird der Methode jedoch nicht null übergeben, sondern der zusammengebaute Parameterstring post_field_str. Dadurch werden die Formularfeldinhalte an den Server bzw. die dort aufgerufene Adresse übertragen.

Sofern nicht anders angegeben, steht der Inhalt dieser Seite unter Lizenz Creative Commons Attribution-ShareAlike 3.0 License