AJAX Timeout Exceptions

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • AJAX Timeout Exceptions

    Vorangegegange: Dieser Thread

    Habe nun ein paar buggy Erscheinungen:
    Woran kann es liegen, wenn ich beim Klick auf den Login-Button kein Ergebis (also login=ok oder so) angezeigt bekomme, sondern erst beim 2ten Mal klicken?

    Desweiteren wundert mich, wenn ich schnell hintereinander ENTER druecke bekomm ich folgende Meldung angezeigt. Was mach ich falsch?

    Method Not Allowed
    The requested method POST is not allowed for the URL /domain.de/v1.0/index.html.



    Hier mal mein Ajax-Ausschnitt:

    Quellcode

    1. var loginReq = getXMLHttpRequestObject();
    2. function ajax(send) {
    3. loginReq.onreadystatechange = function() {
    4. if ((loginReq.readyState == 4) && (loginReq.status == 200))
    5. result = loginReq.responseText;
    6. }
    7. loginReq.open('POST', 'inc/func_login.php', true);
    8. loginReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    9. loginReq.send(send);
    10. }
    11. function loginUser() {
    12. var username = document.getElementById('benutzer').value;
    13. var passwort = document.getElementById('passwort').value;
    14. ajax('benutzer='+username+'&passwort='+passwort);
    15. setTimeout("loginHandle()", 500);
    16. }
    17. function loginHandle() {
    18. // Response-String austeilen in Feld login und aktiv
    19. var tmp = result.split('|');
    20. login = tmp[0] == 'true' ? true : false;
    21. aktiv = tmp[1] == 'true' ? true : false;;
    22. var ob = document.getElementById('message');
    23. if(login) {
    24. if(aktiv) {
    25. ob.innerHTML = 'login = ok';
    26. // Weiterleitung in eingelogten Bereich
    27. //document.location.href = "";
    28. } else {
    29. ob.innerHTML = 'Benutzer-Konto wurde deaktiviert.';
    30. }
    31. } else {
    32. ob.innerHTML = 'Login fehlgeschlagen';
    33. }
    34. }
    Alles anzeigen
  • also erstmal die voraussetzung:
    den klick fängst du vermutlich mit folgendem ab:

    Quellcode

    1. onsubmit="loginUser();return false"

    korrekt?

    jetzt versteh ich aber nicht, warum du deine loginHandle() mit 300ms Verzögerung aufrufst?
    Die soll doch eigentlich, genau dann aufgerufen werden, wenn ajax eine Antwort erhält

    mach es doch lieber so:
    * entferne die setTimeout Methode und starte loginHandle mit dem Trigger

    Quellcode

    1. loginReq.onreadystatechange = loginHandle;


    in der loginHandle Funktion musst du natürlich noch die 2 zeilen von oben wiederverwenden

    Quellcode

    1. function loginHandle() {
    2. if ((loginReq.readyState == 4) && (loginReq.status == 200)) {
    3. result = loginReq.responseText;
    4. // Response-String austeilen in Feld login und aktiv
    5. var tmp = result.split('|');
    6. login = tmp[0] == 'true' ? true : false;
    7. ....
    8. }
    9. }
    Alles anzeigen
  • "nilitsch" schrieb:

    Desweiteren wundert mich, wenn ich schnell hintereinander ENTER druecke bekomm ich folgende Meldung angezeigt. Was mach ich falsch?

    Method Not Allowed
    The requested method POST is not allowed for the URL /domain.de/v1.0/index.html.


    Diesen Fehler erhältst du vermutlich, weil dein Browser nur eine gewisse Anzahl von gleichzeitigen Anfragen zulässt

    umgehen kannst du das so

    Quellcode

    1. try {
    2. deineFunktion();
    3. } catch(e) {
    4. setTimeout("deineFunktion()", 500);
    5. }


    hab mal einen Wiki Beitrag dazu verfasst
    [coderwiki]HowTos/Ajax-zu-viele-Anfragen[/coderwiki]
  • Ja genau das war das Handicap. Mal wieder ein super DANKE DANKE, dOnUt.
    Der Timeout war der Übeltäter :D
    Das ich da mit dem readystatechange arbeiten muss habe ich übersehen, weil ich oben schon readystatechange verwendet habe. Aber jetzt ist es mir schon klar.
    So funktionierts:

    Quellcode

    1. // globale Variablen
    2. var result, login = false, aktiv = false;
    3. // globales XMLHttpRequest-Objekt erzeugen
    4. var loginReq = getXMLHttpRequestObject();
    5. function ajax(send) {
    6. loginReq.open('POST', 'inc/func_login.php', true);
    7. loginReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    8. loginReq.send(send);
    9. }
    10. function loginUser() {
    11. var username = document.getElementById('benutzer').value;
    12. var passwort = document.getElementById('passwort').value;
    13. ajax('benutzer='+username+'&passwort='+passwort);
    14. loginReq.onreadystatechange = loginHandle;
    15. }
    16. function loginHandle() {
    17. if ((loginReq.readyState == 4) && (loginReq.status == 200)) {
    18. result = loginReq.responseText;
    19. // Response-String aufteilen in Feld login und aktiv
    20. var tmp = result.split('|');
    21. login = tmp[0] == 'true' ? true : false;
    22. aktiv = tmp[1] == 'true' ? true : false;
    23. // Debug-Ausgabe
    24. // alert(login + " " + aktiv);
    25. var ob = document.getElementById('message');
    26. if(login) {
    27. if(aktiv) {
    28. ob.innerHTML = 'login = ok';
    29. // Weiterleitung in eingelogten Bereich
    30. document.location.href = "./files.php";
    31. } else {
    32. ob.innerHTML = 'Ihr Benutzer-Konto wurde deaktiviert';
    33. }
    34. } else {
    35. ob.innerHTML = 'Bitte wiederholen Sie Ihre Eingabe noch einmal';
    36. }
    37. }
    38. }
    Alles anzeigen


    Aber das mit diesen zu häufigen Anfragen habe ich noch nicht gecheckt:
    Die Funktion, die ich aufrufe mit

    Quellcode

    1. onsubmit="loginUser();return false"

    müsste ich ja in den try{}catch{} Block setzen. Aber ich kann doch in dem onsubmit keine try und catch Anweisungen schreiben?
  • naja.. sinniger wäre es, wenn du ne javascript variable setzt die den erneuten aufruf des logins unterbindet - 1 login pro sekunde sollte schließlich reichen

    aber zu deiner frage:
    das try catch gerüst klappt überall..
    um so weiter "oben" du den fehler abfängst, um so globaler kannst du die funktion einfach nochmal starten

    Quellcode

    1. try {
    2. ajax('benutzer='+username+'&passwort='+passwort);
    3. } catch(e) {
    4. //innerhalb der ajax funktion, oder eine unterfunktion
    5. //gabs ein fehler.. also versuchs erneut
    6. setTimeout("ajax('benutzer="+username+"&passwort="+passwort+"') ", 500);
    7. }
  • Ok...leuchtet ein. Ich setz die Funktion in der ich den POST aufrufe in den try-catch-Block. Soweit läuft es jetzt auch.

    Im Mozillas Firebug bekomm ich folgende Fehlermeldung ausgegeben:

    [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.status]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://meineanwendung.de/inc/inc_ajax_login.js :: loginHandle :: line 30" data: no]

    uncaught exception: [Exception... "Component returned failure code: 0x804b000f [nsIXMLHttpRequest.setRequestHeader]" nsresult: "0x804b000f (<unknown>)" location: "JS frame :: http://meineanwendung.de/inc/inc_ajax_login.js :: ajax :: line 24" data: no]


    Was kann ich dagegen tun? Oder muss ich damit leben, weil einfach die Exception abgefangen wurde?
  • Welche Zeile meinst Du?
    Den XMLHttpRequest hole ich mir ueber die Funktion getXMLHttpRequestObject();

    Ich habe imprinzip meine JavaScript Dateien in der index.html ausgelagert. getXMLHttpRequest.js und login.js.

    Was anderes:
    Ein paar Post zuvor haben wir uns ueber das googlemail frontend unterhalten.
    anstatt die seite mit <a href="url"> zu wechseln schreibst du dir einfach eine ajax funktion die url() in dein hauptdiv lädt


    So will ich es jetzt auch versuchen. Aber wie lade ich in ein DIV eine URL? Um innerhalb des divs zuzugreifen verwende ich doch innerHTML. Hast Du zufaellig ein Tutorial dazu?
  • Danke für den Wiki.

    In meiner Main-Seite habe ich einen div für die Navigationsleiste, die dynamisch je nach Benutzer geladen werden soll, sowie das Main-Div mit dem Content.
    Wenn ich jetzt aber in meiner ajax_login.js zweimal hintereinander die geturl() Methode aufrufe bekomm ich eine Fehlermeldung. Bei einmaligem Aufruf funktionierts.

    Quellcode

    1. geturl('inhalt', 'content.php');
    2. geturl('sidebar', 'sidebar.php');


    [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.status]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://localhost/FS_Reloaded/v1.0/inc_frame_loader.js :: anonymous :: line 9" data: no]
    -> 9: if ((req.readyState == 4) && (req.status == 200)) {

    [Exception... "Component returned failure code: 0x804b000f [nsIXMLHttpRequest.setRequestHeader]" nsresult: "0x804b000f (<unknown>)" location: "JS frame :: http://localhost/FS_Reloaded/v1.0/inc_frame_loader.js :: geturl :: line 14" data: no]
    -> 14: req.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );

    Das frage ich mich eigentlich auch wie handelt man denn am Besten mehrere XMLHttpRequest innerhalb einer Anwendung? Bzw. gleichzeitig?

    Ausserdem möchte ich eine Loading... -Anzeige einbauen, die angezeigt wird, wenn was passiert. Dies habe ich auch in meiner ajax_login.js in der Funktion loginHandle eingebaut bevor ich meinen Login-Request auswerte. Aber irgendwie funktioniert das nicht so flüssig. Manchmal wirds angezeigt und manchmal nicht??
    Was mach ich da falsch? Ich frag doch nach dem readyState ab??

    Quellcode

    1. function loginHandle() {
    2. // Loading-Status abfragen
    3. var status = document.getElementById('status');
    4. if (loginReq.readyState < 4) status.innerHTML = "loading...";
    5. if (loginReq.readyState == 4) status.innerHTML = "";
    6. // Login-Anfrage auswerten
    7. if ((loginReq.readyState == 4) && (loginReq.status == 200)) {
    8. ...



    Btw.... dOnUt, ist Deine Amazon-"Beschenk mich"-Wunschzettel noch aktuell??

    Gruss,
    nilitsch
  • um ehrlich zu sein, weiß ich die ideale Zeit nicht - ich glaube das hängt von internet geschwindigkeit, betriebsystem und browser ab - ich nehm meistens etwas zwischen 500 und 750ms

    wenn ich mehrere requests gleichzeitig starten will, dann mach ich das meistens indem ich die exception fange und die funktion darüber erneut aufrufe
    nicht sehr sauber, aber kurz im code

    weitere möglichkeit:

    Quellcode

    1. setTimeout("geturl('inhalt', 'content.php')", 0);
    2. setTimeout("geturl('sidebar', 'sidebar.php')", 750);

    das sind zwar 0,75 Sekunden verzögerung
    ABER bau dir doch einfach eine "loading" grafik ins div..
    sobald der ajax content geladen wird, verschwindet die ja wieder
    ich finde das sieht eigentlich ganz schick aus ;)

    Quellcode

    1. <div id="sidebar"><img src="loading.gif" alt="page is loading" /></div>


    nächste lösung: warteschlange
    die "großen" ajax frameworks haben meistens eine warteschlange implementiert.
    ein Datentyp, der die aufzurufenden Funktionen speichert und nach abarbeitung immer die nächste aufruft

    du rufst die ajax funktion also nicht direkt auf, sondern speicherst sie in einer queue
    die queue arbeitet dann mit einem trigger

    Quellcode

    1. function ajax() {
    2. trigger = false; //d.h. es dürfen keine weiteren funktionen aufgerufen werden
    3. ...
    4. }
    5. if ((loginReq.readyState == 4) && (loginReq.status == 200)) {
    6. trigger = true; //jetzt dürfen sie wieder
    7. ...
    8. }


    PS: Wunschliste ist noch aktuell ;)
  • Gut zu wissen :wink:

    Mein Projekt wird auch was grösseres werden. Soll es zumindest :)
    Da ich mit mehren divs arbeiten und diese auch immer neu laden werde, werde ich vermutlich mit haufenweise Requests zu tun haben. Auf der einen Seite ein Menü, das weiter aufklappen soll und je nach Auswahl den Inhalt vom Mainframe (Maindiv) ladet.
    Hierfür müssen die verschiedenen Benutzeraktionen gehandelt werden. Also summa sumarium ein Haufen Requests.

    Ich glaube ich sollte mich mit dieser Warteschlange-Idee anfreunden. Hast Du irgendwelche Infos darüber?
  • So eine Ladeanzeige, wie Du es beschrieben hast möchte ich auch einbauen. Aber nichtfür jedes div, sondern generell in der oberen rechten Ecke. Es soll einfach nur eingeblendet werden, das etwas geladen wird.

    Wenn ich aber nun die handleLogin-Funktion beim readystatechange aufrufe, und ich über loginReq.readyState den Status des Requests auswerte und daraus resultierend mein Status-Div mit "loading..." anzeigen möchte, läuft das nur ab und zu. Meintens zeigt er mir nichts an.

    Quellcode

    1. function loginHandle() {
    2. //alert(loginReq.readyState);
    3. Loading-Status abfragen
    4. var status = document.getElementById('status');
    5. if (loginReq.readyState < 4) status.innerHTML = "loading...";
    6. if (loginReq.readyState == 4) status.innerHTML = "";
    7. // Login-Anfrage auswerten
    8. if ((loginReq.readyState == 4) && (loginReq.status == 200)) {
    9. result = loginReq.responseText;
    Alles anzeigen


    Vielleicht wäre es am besten ich bündele diese Loading-Anzeige aus, so dass ich sie generell für alle Requests verwenden kann. Ich das so machbar?
  • naja.. objektorientierte javascript warteschlange.. gibts bestimmt schon was fertiges

    generell ist die frage ob du alles selber schreiben willst
    wenn du alles fertig hast, fällt dir am ende ein, dass ein paar optische effekte noch klasse wären

    und dann greifst du am ende doch auf ein framework zurück
    Da wären z.B. http://prototype.conio.net
    oder Scriptaculous (basiert auf prototype)

    aber zu dem problem mit großen portalen: Wie wärs wenn du mehrere inhalte über eine anfrage schickst?

    hier werden auch 3 divs aktualisiert
    [coderwiki]HowTos/Ajax-Inhalte-mit-PHP-nachladen[/coderwiki]
  • Moin dOnUt,

    wenn ich die meine divs mit geturl(); send ich meinen Request ja an die fetch.php:

    Quellcode

    1. echo file_get_contents($_POST['url']);


    Wenn ich aber eine php-Datei sende (laden möchte), wird das PHP nicht ausgeführt. Wie kann ich das lösen?

    Ausserdem verhädere ich mich, glaube ich, ein wenig mit meinen divs. Wenn ich zum Beispiel ein Formular in meinen Main-Div lade, und anschliessend auf meinen submit-Button klick, schmeisst er mich auf die Anfangsseite (login) zurück! Gibt es dazu lösungsansätze?
  • lädst du die php datei direkt?
    wenn du die interpretierte php datei laden willst, musst du vor den dateinamen noch deine domain hinzufügen

    Quellcode

    1. file_get_contents('http://domain.tld/file.php');


    zu deinem formular problem - wenn du eine reine ajax anwendung schreibst, dann muss auch alles ajax bleiben
    ein html formular submit führt zum neuladen er seite, die in action angegeben wird

    wie du das abfängst, ist im ajax login code beschrieben

    Quellcode

    1. <form onsubmit="funktionsaufruf(); return false">
  • Mmmmh... wenn ich PHP verwende, muss ich wirklich die genaue URL angeben? Würde gern die Programmierung so weit wie möglich modular umsetzen, ohne grosse Anpassungen vornehmen zu müssen, wenn ich die Dateien später auf einen anderen Server laden möchte.

    Desweiteren:
    Ich habe immer noch Probleme mit meinen divs. Wenn ich die Seiten im Single-Modus lade (also nicht im Main-Div der Hauptseite), dann funktioniert alles prima.... auch mein ajax.
    Wenn ich aber die Seite in mein Main-Div einfüge (nach erfolgtem Login rufe ich die Javascript loadSite()-Funktion auf und lade mit geturl in mein Main-Div), dann funktioniert gar nichts.
    Dort sollte dann z.B. eine Ajax/Javascriptfunktion ausgeführt werden, z.B. showDetails(). Ich bekomme die Fehlermeldung angezeigt showDetails is not defined.

    Woran kann das liegen?
  • ich weiß ja nicht wie du den "ajax frame" frame anwendest
    vielleicht erhältst du einen ungültigen html code

    der ajax frame ist nicht für externe urls gedacht
    wenn web.de in ein div objekt geladen wird, sieht das dann in etwa so aus

    Quellcode

    1. <html><body>
    2. <div id="content">
    3. <html>
    4. <head><title>web.de</title>
    5. ....
    6. </html>
    7. </div>
    8. </body></html>


    Zum einbinden von php: Das problem ist, dass du fertig geparste php seite brauchst - geparset wird aber von apache - und der apache wird über die URL angesprochen

    aber eine url in der konfiguration anzugeben, sollte dich wirklich nicht daran hindern, das einzusetzen