biber: eigener Chat-Versuch per Ajax: Seite lädt plötzlich neu

Hallo,

derzeit versuche ich einen eigenen Chat zu entwickeln auf Basis von PHP, MySQL und Ajax. Im IE6 funktioniert alles wie es sein sollte, doch der Firefox  (bei mir Vers. 2.0.0.13) bereitet Probleme:

Gibt man mehrere Zeilen hintereinander ein (meistens der Fall) - manchmal geschieht es aber auch schon beim ersten Versuch - lädt die ganze Seite plötzlich neu und an die url wird ein Fragezeichen angehangen. Statt "chat.php" steht dort also "chat.php?".

Der Chat ist bei Strato installiert, also nicht lokal. Leider fällt mir überhaupt nichts auf, was den Fehler verursachen könnte. So hoffe ich, dass ihr mir helfen könnt ;)

Folgendermaßen sieht der javascript-Code aus:

-----------------------------------------------
var xmlHttp=null;

try
 {
 // Firefox, Opera 8.0+, Safari
 xmlHttp=new XMLHttpRequest();
 }
catch (e)
 {
 // Internet Explorer
 try
  {
  xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
  }
 catch (e)
  {
  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
 }

// aktuelle Daten laden
loadData();

// alle 3 Sekunden neue Daten holen
setInterval("loadData()",3000);

function loadData()
{
 if (xmlHttp) {
     xmlHttp.open('GET', 'getdata.php?latestID='+latestID, true);
     xmlHttp.onreadystatechange = function () {
         if (xmlHttp.readyState == 4) {

// gekürzt, da es wohl den Rahmen sprengen würde. Mittels getdata.php wird
// ein String zurückgeliefert, welcher alle neuen Nachrichten sowie die
// aktuelle Nutzerliste beinhaltet.

}
     };
     xmlHttp.send(null);
 }
}

function saveData()
{
if (xmlHttp) {
    message = encodeURIComponent(document.getElementById("inputMessage").value);
    var param='message=' + message;
    xmlHttp.open("POST", "setdata.php", true);

xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlHttp.setRequestHeader("Content-length", param.length);
    xmlHttp.setRequestHeader("Connection", "close");

// make the server request
    xmlHttp.send(param);
}

// Message-Eingabefelder leeren und Focus setzen
document.getElementById("inputMessage").value = '';
document.getElementById("inputMessage").focus();
}
-----------------------------------------------

Mein bisheriger Gedanke war, dass sich das Speichern der neuen, geschriebenen Nachricht vielleicht mit dem Laden der Nachrichten aus der Datenbank überschneidet. Ein Verringern des Intervalls auf 1 Sekunde führt dazu, dass das Neuladen der Seite sofort ausgeführt wird. Ein Erhöhen des Intervalls lässt die Vermutung zumindest gut aussehen: der Fehler tritt nicht zu häufig auf. Das Schlechte daran ist natürlich, dass die Geschwindigkeit m.E. nicht mehr akzeptabel ist und der Fehler kann immernoch auftreten.

Wie kann man diesen Fehler beheben? Bei meiner Suche im Netz habe ich bislang nichts gefunden, was mich der Lösung näher brachte.

Gruß,
Christian

  1. Hi,

    Gibt man mehrere Zeilen hintereinander ein (meistens der Fall) - manchmal geschieht es aber auch schon beim ersten Versuch - lädt die ganze Seite plötzlich neu und an die url wird ein Fragezeichen angehangen. Statt "chat.php" steht dort also "chat.php?".

    Das deutet in aller Regel darauf hin, dass ein Formularversand (per GET), der eigentlich per Script unterbunden werden sollt, doch stattgefunden hat - weil im Script ein Fehler auftrat, so dass das das Abschicken unterbindende return false nicht mehr zur Ausfuehrung kam.

    MfG ChrisB

    1. Das deutet in aller Regel darauf hin, dass ein Formularversand (per GET), der eigentlich per Script unterbunden werden sollt, doch stattgefunden hat - weil im Script ein Fehler auftrat, so dass das das Abschicken unterbindende return false nicht mehr zur Ausfuehrung kam.

      MfG ChrisB

      Guten Morgen,

      ich danke Dir. Daran hätte ich nie gedacht.

      Im aufrufenden Formular habe ich sogar vergessen, die Methode (GET oder POST) anzugeben. Nachdem ich endlich die Fehler-Konsole im Firefox gefunden habe (man lernt scheinbar nie aus :D ) habe ich auch das Hauptproblem gefunden:

      uncaught exception: [Exception... "Component returned failure code: 0x804b000f [nsIXMLHttpRequest.setRequestHeader]" nsresult: "0x804b000f (<unknown>)" location:...

      Also hatte ich scheinbar mit der Vermutung der Überschneidung nicht ganz Unrecht: Während des Aufrufs von "xmlHttp.setRequestHeader" in der Funktion "saveData()" (nun ist es zumindest eine) wird scheibar bereits in der Methode "loadData()" auf das Request-Objekt zugegriffen. Wenn ich alles richtig verstanden habe, bedeutet der obige Fehlercode nichts anderes als den Versuch eines doppelten Zugriffes.

      "saveData()" habe ich nun folgendermaßen abgeändert:

      function saveData()
      {
      if (xmlHttp) {
          message = encodeURIComponent(document.getElementById("inputMessage").value);
          var param='message=' + message;
          xmlHttp2.open("POST", "setdata.php", true);

      xmlHttp2.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
          xmlHttp2.setRequestHeader("Content-length", param.length);
          xmlHttp2.setRequestHeader("Connection", "close");

      // make the server request
          xmlHttp2.send(param);
      }

      // Message-Eingabefelder leeren und Focus setzen
      document.getElementById("inputMessage").value = '';
      document.getElementById("inputMessage").focus();

      return false;
      }

      Dafür habe ich nun zu Beginn ein zweites Objekt namens "xmlHttp2" erzeugt (genauso wie das andere auch). Damit wird der Fehler grob unterbunden.

      "Grob", weil bei einer versehentlichen doppelten Betätigung der Enter-Taste der gleiche Fehlercode erzeugt wird. Als Zugabe gibt es dann auch noch den Fehler "xmlHttp is not defined".

      Bei der eigentlichen Suche nach dem Fehlercode bin ich auf folgender Seite über diesen Workaround gestolpert:
            try {
             deineFunktion();
            } catch(e) {
             //Fehler abgefangen
             //Funktion mit Verzögerung erneut aufgerufen
             setTimeout("deineFunktion()", 500);
            }

      Angewandt auf "saveData()":

      function saveData()
      {
      try{
      if (xmlHttp) {
          message = encodeURIComponent(document.getElementById("inputMessage").value);
          var param='message=' + message;
          xmlHttp.open("POST", "setdata.php", true);

      xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
          xmlHttp.setRequestHeader("Content-length", param.length);
          xmlHttp.setRequestHeader("Connection", "close");

      // make the server request
          xmlHttp.send(param);
      }

      // Message-Eingabefelder leeren und Focus setzen
      document.getElementById("inputMessage").value = '';
      document.getElementById("inputMessage").focus();
      }
      catch (e) { setTimeout("saveData()", 500); }
      return false;
      }

      So gibt es kein Neuladen der Seite mehr.

      Zum Testen versuche ich, möglichst schnell ein Zeichen einzugeben und mit Enter abzuschicken. Dieses halt möglichst schnell und oft hintereinander. Der unschöne Nebeneffekt bei diesem "Workaround" verschwindet kurz die Nutzerliste, welche in "loadData()" komplett erneuert wird, und taucht dann wieder auf. Vermutlich aufgrund des Timeouts.

      Das Problem scheint damit erst einmal gelöst zu sein - es sei denn, es gibt noch einen "besseren" Weg. Die blinkende Nutzerliste sollte wohl bei "normaler" Chat-Benutzung nicht passieren.

      Ich danke Dir vielmals für den Hinweis!

      Gruß,
      Christian

      1. Der Vollständigkeit zuliebe: Beide Varianten zu mischen, also sowohl ein zweites Request-Objekt als auch der try/catch-Block in der saveData()-Funktion, scheint die beste Lösung zu sein, die mir einfällt.

        Mit try/catch-Block, aber nur einem Request-Objekt, kommt es doch zu vielen Hängern, wenn man ständig das Glück hat, den Intervall von loadData() zu erwischen. Mit einem zweiten Request-Objekt kommt es nur zu einem Hänger, wenn man ganz schnell etwas hintereinander eingeben möchte. Bei normalem Chatverhalten sollte dies m.E. zu verkraften sein.

        1. Der Vollständigkeit zuliebe: Beide Varianten zu mischen, also sowohl ein zweites Request-Objekt als auch der try/catch-Block in der saveData()-Funktion, scheint die beste Lösung zu sein, die mir einfällt.

          die beste Lösung ist, einen suaberen Ablauf zu programmieren, wo solche Nebenläufigkeiten nicht auftreten können. Z.B. in dem man den Zugriff auf die Variabel einfach blockt solange die Anfrage noch nicht fertig ist.

          Struppi.

          1. die beste Lösung ist, einen suaberen Ablauf zu programmieren, wo solche Nebenläufigkeiten nicht auftreten können. Z.B. in dem man den Zugriff auf die Variabel einfach blockt solange die Anfrage noch nicht fertig ist.

            Struppi.

            Das stimmt natürlich. Doch wie macht man sowas? Da ich mit Ajax noch ziemlich am Anfang stehe, stehe ich an dieser Stelle ziemlich auf dem Schlauch (sofern dieser bei mir überhaupt schon vorhanden ist :D ).