Linuchs: Ajax liefert nicht den aktuellen Dateiinhalt

Moin,

ich experimentiere mit einem Liederbuch im HTML-Format. Master (Chorleiter) und Slaves (Sänger) laden das Buch in den Browser.

Der Master kann auf eine Seite klicken, Liederbuch-Titel und Lied-Nr. wird per Ajax und php in eine Textdatei auf dem Server geschrieben:

http://osmer.de/musik/liederbuecher/kalles_liederbuch_test.htm#lied_04

Das funktioniert, in Filezilla kann ich den Inhalt der Datei sehen.

Alle Slaves rufen in regelmäßigen Abständen per Ajax diese Datei auf (deshalb stieß ich auf setInterval) und sollen auf die verlangte Seite wechseln.

Jedoch „sieht“ Ajax stets den alten Stand der Textdatei. Was läuft in getLiedtext falsch?

function setLiedtext( lied_URL ) {
//alert( "[" +lied_URL +"]" );

  /* *******************************************************
   * Initialisierung beim ersten Aufruf nach Programm-Start
   * ******************************************************* */
  if ( setLiedtextVar.requestObj == "leer" ) {
    setLiedtextVar.requestObj    = makeRequestObject( "setLiedtext.js - setLiedtext" ); // makeRequestObject() ist in standard.js
  }
  var url = "./ajax/setLiedtext.php?lied_URL=" +encodeURIComponent(lied_URL);
  console.log( "[" +url +"]" );
//setLiedtextVar.obj.title = "setLiedtext.js " + url;
  setLiedtextVar.requestObj.open('post', url, true);                  // Request öffnen
  setLiedtextVar.requestObj.send(null);                               // Request senden
/*
  setLiedtextVar.requestObj.onreadystatechange = setLiedtextZeigen;
*/
}



function getLiedtext() {
  /* *******************************************************
   * Initialisierung beim ersten Aufruf nach Programm-Start
   * ******************************************************* */
  if ( setLiedtextVar.requestObj == "leer" ) {
    setLiedtextVar.requestObj    = makeRequestObject( "setLiedtext.js - getLiedtext" ); // makeRequestObject() ist in standard.js
  }
  var url = "./ajax/liederbuch.txt";
  setLiedtextVar.requestObj.onreadystatechange = setLiedtextZeigen;
  setLiedtextVar.requestObj.open('get', url, true);                   // Request öffnen synchron (false) oder asynchron (true)
  setLiedtextVar.requestObj.send(null);                               // Request senden
  console.log( "[" +url +"]" );
}

function setLiedtextZeigen() {
  // Request-Status hat sich geaendert
  if ( setLiedtextVar.requestObj.readyState == 4 && setLiedtextVar.requestObj.status == 200 ) {
    console.log( setLiedtextVar.requestObj.responseText );
  }
}

Danke schon mal.

Pfiffiger wäre wohl, dass die Slaves nicht ständig vergeblich (im Sinne: Es hat sich nichts geändert) die Datei abrufen, sondern im Falle einer Änderung informiert werden.

Diese Technik kenne ich aber nicht. Geht sowas bei 30 - 50 Slaves und wo kann ich mich einlesen?

Linuchs

Edit: Habe die Textdatei gelöscht. Ajax meldet wacker weiter alle 10 sec den alten Stand. Scheint überhaupt nicht zu lesen.

  1. Mach bitte mal das Netzwerkpanel auf und schau Dir die Requests genauer an. Insbesondere die Header.

  2. Lieber Linuchs,

    ich habe Deinen Quelltext nicht auf den ersten Blick verstanden. Mir ist auch nicht klar, warum Du XMLHttpRequest-Objekte verwendest, wo es doch inzwischen das viel komfortablere (und besser zu lesende) fetch gibt.

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix,

      ich habe Deinen Quelltext nicht auf den ersten Blick verstanden. Mir ist auch nicht klar, warum Du XMLHttpRequest-Objekte verwendest, wo es doch inzwischen das viel komfortablere (und besser zu lesende) fetch gibt.

      Ja stimmt. In dem Zusammanhang: Leider haben beide Möglichkeiten den Nachteil, dass sie nur in Serverumgebung also nicht lokal ohne Server funktionieren, oder hat sich da mittlerweile was getan? Wäre interessant zu wissen.

      Gruss
      Henry

      --
      Meine Meinung zu DSGVO & Co:
      „Principiis obsta. Sero medicina parata, cum mala per longas convaluere moras.“
      1. Hallo Henry,

        Ja stimmt. In dem Zusammanhang: Leider haben beide Möglichkeiten den Nachteil, dass sie nur in Serverumgebung also nicht lokal ohne Server funktionieren, oder hat sich da mittlerweile was getan? Wäre interessant zu wissen.

        du kannst mit

        about:config öffnen
        security.fileuri.strict_origin_policy auf false setzen
        

        den Firefox dazu bringen, XMLHttpRequests auch mit dem file-Protokoll zuzulassen.

        Gruß
        Jürgen

        1. Hallo JürgenB,

          das geht natürlich, aber immer diese Umstellerei. Ich hatte deshalb mal ein anderes Konstrukt, glaube mit Iframes, für sowas hier gebastelt und auch ein längere Diskussion mit Gunnar darüber, der damals auch Fetch() empfahl.

          Gruss
          Henry

          --
          Meine Meinung zu DSGVO & Co:
          „Principiis obsta. Sero medicina parata, cum mala per longas convaluere moras.“
      2. Hallo Henry,

        welche Schwierigkeit besteht beim Aufsetzen eines lokalen Servers? Dedlfix bringt für das Offline Wiki bspw. einen NGINX mit, als reine Copy-Installation.

        Wenn du einen Windows PC hast, kannst Du den IIS aktivieren.

        Oder lässt php -S 127.0.0.1:8088 als Minimalserver auf Port 8088 laufen, für einen lokalen Abruf statischer Ressourcen reicht das immer.

        Wenn Du natürlich irgendwelchen Menschen via Fileshare eine html-Datei mit eingebautem JavaScript geben willst, das auf anderweitige Ressourcen zugreifen soll, tja, dann ist das vielleicht doch das falsche Medium. Oder der falsche Workflow - dafür sollte man wirklich einen Webserver aufsetzen.

        Aber es gibt ja auch Unternehmen, die ihre ganze EDV mit Excel und VBA erledigen... für einen guten Schmied ist alles ein Hammer.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf,

          ... für einen guten Schmied ist alles ein Hammer.

          nicht ganz: Ein guter Schmied kann alles mit dem Hammer. 😀

          Gruß
          Jürgen

  3. Hallo Linuchs,

    die Liederbücher sind immer noch in der Experimentalphase? Damit warst Du doch 2015 schon unterwegs 😉

    Wieauchimmer - Mitleser dürfte davon ausgehen, dass hier Caching im Spiel ist. Möglicherweise liest der Browser gar nicht vom Server, sondern "befriedigt" die Anfrage direkt aus dem eigenen Cache.

    Der Server müsste für diese Datei einen entsprechenden Cache-Control Header setzen.

    Push-Verfahren würden mit Websockets oder Server-Sent Events realisierbar sein. Nicht trivial. Der Server muss das unterstützen, und die klassische Apache/PHP Kombi tut das nicht. Eine Anwendung, die Websockets nutzt, ist serverseitig ein Langläufer, ganz das Gegenteil eines rein-machwas-raus HTTP Requests.

    Es gibt einen Websocket-Server für PHP, Ratchet. Keine Ahnung ob der was taugt, noch nie probiert. Da startest Du die PHP Appliation aber separat, nicht unter Apache.

    Bei 30-50 Clients solltest Du beim Polling bleiben. Wenn jeder Client einmal pro Sekunde pollt, sollte das handhabbar bleiben. Wichtig wäre eventuell, dass die eigentlichen Seiten schon vor dem Umblättern auf den Clients sind und nur die Seitennummer geholt werden muss, denn andernfalls würden alle Clients auf einmal eine Liederbuchseite downloaden wollen. Wenn die Noten als Grafik gezeigt werden, könnte das zu viel des Volumens werden.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      Möglicherweise liest der Browser gar nicht vom Server, sondern "befriedigt" die Anfrage direkt aus dem eigenen Cache.

      Ja, den Verdacht hatte ich auch ...

      Inzwischen habe ich hin und her getestet. Mal hat's geklappt, mal nicht.

      Bei Schreiben des Textes habe ich onreadystatechange ignoriert, also auch responseText nicht abgefragt.

      Vielleicht wird der vom nächsten Request (Abfrage der geschriebenen Datei) gar nicht überschrieben?

      Frage also den responseText jetzt auch beim Schreiben der Datei ab.

      Scheint jetzt zu funktionieren, aber verstanden habe ich das nicht. Unbefriedigend, wenn man nur durch Versuch und Irrtum eine Zufalls-Lösung findet.

      Linuchs

      1. Scheint jetzt zu funktionieren, aber verstanden habe ich das nicht. Unbefriedigend, wenn man nur durch Versuch und Irrtum eine Zufalls-Lösung findet.

        Mann, mach bitte endlich das Netzwerkpanel auf und guck Dir an, was passiert!

        1. Mit [Strg][Shift][K] öffne ich im FF die Konsole. Aber den Begriff Netzwerk finde ich dort nicht. Was meinst du?

          Edit: Doch - da ist Netzwerkanalyse. Werde mich damit befassen, ist mir neu.

          Übertragen aus Cache .... Wie kann ich das ändern?

          1. Übertragen aus Cache .... Wie kann ich das ändern?

            Gibt mehrere Optionen. Unsauber, aber in Deinem Fall hier IMHO völlig in Ordnung: häng einfach an den Request einen Timestamp dran.

            1. okay, inzwischen gemacht. Scheint die Lösung zu sein.

              1. okay, inzwischen gemacht. Scheint die Lösung zu sein.

                Sollte klappen, ja. DIE Lösung würde ich es nicht nennen wollen, eher einen (tragbaren) Workaround. Wenn Du es schöner machen und dabei lernen willst, dann schau Dir die Header im Netzwerkpanel genauer an und Recherchiere deren Bedeutung / Konsequenzen…

    2. Wichtig wäre eventuell, dass die eigentlichen Seiten schon vor dem Umblättern auf den Clients sind

      Ja, darauf hätte ich sowieso geachtet, bin aber noch nicht so weit.

      Gestern habe ich Stunden mit einem Musiker vergeblich versucht, die App „MobileSheets“ mit zwei Tablets zum Laufen zu bringen.

      Die soll genau das tun: Master gibt vor, Slaves springen auf den Titel.

      Jedes Tablet hat die Lieder local geladen und per Bluetooth oder selbst kreiertem WLAN soll man unabhängig sein vom Web. Was für unbekannte Auftrittsorte natürlich von Vorteil ist.

      Weißt du, ob ein Linux-Laptop ein eigenes WLAN kreiren und den Server spielen kann? Dann hätte ich ein tragbares Web ;-)

      Und jeder kann sich per Browser einklinken ohne vorher laden zu müssen.

      Linuchs

      1. Hallo Linuchs,

        Weißt du, ob ein Linux-Laptop ein eigenes WLAN kreiren und den Server spielen kann? Dann hätte ich ein tragbares Web ;-)

        XAMPP gibt es m. W. auch für Linux, heißt dort LAMPP.

        Bis demnächst
        Matthias

        --
        Du kannst das Projekt SELFHTML unterstützen,
        indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
        1. Hallo Matthias,

          LAMP ist meines Wissens das ursprüngliche Paket. Noch mit einem P. Irgendwann kam Perl hinzu und die Unterstützung für Windows, MacOS und Solaris, und man kreierte den Oberbegriff XAMPP. LAMPP, WAMPP, SAMPP und MAMPP haben sich nicht etabliert.

          Man rät aber davon ab, XAMPP für produktive Umgebungen zu verwenden. Es ist ein Entwickler-Testsystem. Sicherlich kann man XAMPP als Basis verwenden und den Laptop von da ausgehend härten, aber da muss man schon genau wissen was man tut. Es könnte einfacher sein, Apache und PHP selbst zu installieren und dabei den Anleitungen für Produktivsysteme zu folgen.

          Vielleicht wäre statt dessen sogar eine node.js Installation sinnvoll, denn der ist für Websocket-Anwendungen besser geeignet als Apache. Das ist dann nur wieder eine steile, vergletscherte Lernkurve, die für altgediente Pinguine zu flutschig sein kann.

          Rolf

          --
          sumpsi - posui - obstruxi
      2. Hallo Linuchs,

        Weißt du, ob ein Linux-Laptop ein eigenes WLAN kreiren und den Server spielen kann?

        kreieren - sieht genauso bescheuert aus wie kreiren, ist aber richtiger. Man muss es nur richtig aussprechen: kre-ieren, nicht kr🥚-eren

        Das Problem wird nicht Linux sein. Eher der Laptop. Oder auch Linuchs 😉

        Gemacht habe ich es noch nicht, aber Google gibt mir diesen Tipp:

        https://www.pcwelt.de/ratgeber/WLAN-Access-Point-mit-Linux-9895907.html

        Rolf

        --
        sumpsi - posui - obstruxi
  4. Danke für eure Hilfe, der Test funktioniert jetzt wie gewünscht.

    Beim Aufruf der Webseite (Liederbuch) erscheint diese Berechtigungs-Auswahl (fixiert), der Leser kann frei scrollen:

    Nach Aktivierung master wird bei Klick auf die „Teilen“ - Schaltfläche eines Liedes auf dem Web-Server die Adresse dieses Liedes gespeichert. (1 Zugriff).

    Nach Aktivierung slave wird alle paar Sekunden beim Web-Server angefragt, welches Lied anzusteuern ist, der Browser positioniert auf dieses Lied.

    Während der Sitzung kann die Berechtigung geändert werden.

    Wegen Urheberrechts-Abmahnungen sind die Liederbücher leider nicht öffentlich.

    Linuchs

    1. Hallo Linuchs,

      Wegen Urheberrechts-Abmahnungen sind die Liederbücher leider nicht öffentlich.

      Bitte vergewissere dich, ob du nicht vielleicht dennoch gegen das Urheberrechtsgesetz verstößt.

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
  5. Hallo alle,

    in dem Zusammenhang eine total blöde Story. Soeben erlebt.

    Ich wollte mit das Verhalten von fetch beim Caching anschauen. Nun habe ich hier auf meinem Windows PC keinen Apache, aber einen IIS 10. Und natürlich kann ich dagegen auch Webrequests absetzen.

    Ich lade eine data.txt Datei, via Fetch. Oder via XMLHttpRequest. Das ist egal.

    Um das Caching zu steuern, habe ich im IIS die Ausgabezwischenspeicherung für .txt Dateien auf 30 Minuten eingestellt. Und die Folge? Der bescheuerte IIS haut mir mit Freude in jede Response für .txt Dateien ein no-cache in den Cache-Control Header. Folgerequeste an den Server beantwortet er brav mit HTTP 304 - not changed. Aber der Browser cached nix, und ich habe natürlich keine Möglichkeit, mich mit dem Thema browserseitiges Caching zu befassen, wie ich eigentlich wollte.

    Nach 2 Stunden Suche mit den falschen Begriffen weiß ich's nun: der IIS kennt mehr Optionen als sein GUI, man muss die Config-Datei manuell editieren und eine Cache-Location setzen. Default ist: Nur auf dem Server, und das ist das, was das UI da einsetzt. Setzt man "Client", cached nur der Client. Oder "Any", dann kann die Datei überall gecached werden.

    Warum erzähl ich das? Möglicherweise gibt es für den Apache ähnliche Einstellungen. Verbiete clientseitiges Caching, aber liefere HTTP 304, solange die Datei unverändert ist. Sobald sich was verändert, merkt das der IIS und liefert HTTP 200, in den Folgeanforderungen wieder 304. Ein Cache-Buster ist dann nicht erforderlich, das ist eigentlich nur ein Hack. Ich werde allerdings aus der Apache Doku auf die schnelle nicht schlau, ob man ihm das konfigurativ beibringen kann.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf B,

      Nach 2 Stunden Suche mit den falschen Begriffen weiß ich's nun:

      Ich glaub, das hab ich schon mal gefragt: Arbeitest du auch mal?

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
      1. Hallo Matthias,

        *hust*

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo,

          *hust*

          gute Besserung!

          Gruß
          Kalk

  6. @@Linuchs

    Master (Chorleiter) und Slaves (Sänger)

    Was sagen die Sänger:innen dazu, dass sie wie Sklaven behandelt werden?

    Der Master kann auf eine Seite klicken, Liederbuch-Titel und Lied-Nr. wird per Ajax und php in eine Textdatei auf dem Server geschrieben […] Alle Slaves rufen in regelmäßigen Abständen per Ajax diese Datei auf (deshalb stieß ich auf setInterval) und sollen auf die verlangte Seite wechseln.

    AFAIS ist die saubere Lösung dafür: ServiceWorker API, Notifications API, Push API.

    😷 LLAP

    --
    “When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy.’ They told me I didn’t understand the assignment, and I told them they didn’t understand life.” —John Lennon
    1. Was sagen die Sänger:innen dazu, dass sie wie Sklaven behandelt werden?

      Die kennen das gar nicht anders.

      Linuchs

  7. Hi there,

    Pfiffiger wäre wohl, dass die Slaves nicht ständig vergeblich (im Sinne: Es hat sich nichts geändert) die Datei abrufen, sondern im Falle einer Änderung informiert werden.

    Diese Technik kenne ich aber nicht. Geht sowas bei 30 - 50 Slaves und wo kann ich mich einlesen?

    Mit websockets geht das sehr wohl. Damit kannst Du quasi eine "beständige" Verbindung zwischen Server und Client herstellen, damit kann auch der Server eine Änderung/Event/Was auch immer anstossen, ohne daß der Client alle paar Sekunden pollen muß...

    1. Lieber klawischnigg,

      Mit websockets geht das sehr wohl.

      einen passenden Webserver (nicht Apache!) vorausgesetzt.

      Liebe Grüße

      Felix Riesterer

      1. Hi there,

        Mit websockets geht das sehr wohl.

        einen passenden Webserver (nicht Apache!) vorausgesetzt.

        Bist Du Dir sicher? Ich habe da vor ein paar Monaten etwas zusammenprogrammiert (sollte ein corona-bedingter Ersatz für ein Kartenspiel werden) und da hat das anstandlos funktioniert; und ich weiß hundertprozentig, daß ich keinen anderen Webserver als Apachen habe und vor allem weiß ich auch, daß ich dafür kein zusätzliches Modul installiert habe. Afair hat das auf allen drei Webservern funktioniert, die bei mir intern laufen (auf den Raspis hab ich's nicht probiert😉) und da ist auch eine ziemlich alte xampp-Installation drunter...

        1. Hallo klawischnigg,

          mach uns doch nicht bloß den Mund wässrig. Was hast Du denn da genau genutzt? Websockets sind ja prinzipiell nicht das, was dem Indianer von Hause aus mundet. Websockets brauchen einen serverseitigen Dauerläufer. Normalerweise trennt ein Webserver die Daten zweier Clients sehr strikt (zumeist durch konsequentes Wegwerfen nach einem Request), aber für einen Mediator mit WS-Technik musst Du ja eine Instanz haben, die sämtliche Clients kennt und ihre WS-Verbindungen aufrecht erhält.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hi there,

            mach uns doch nicht bloß den Mund wässrig. Was hast Du denn da genau genutzt? Websockets sind ja prinzipiell nicht das, was dem Indianer von Hause aus mundet. Websockets brauchen einen serverseitigen Dauerläufer.

            Tja, gute Frage, ich muß bekennen, daß ich mich da serverseitig nicht wirklich gut auskenne. Die Fragestellung war einfach, ob es möglich ist, daß der Server etwas anstossen kann und da bin ich durch googeln (oder besser, startpagen https://www.startpage.com 😉) auf die websockets gestoßen (die ich in anderem Zusammenhang schon irgendwo einmal verwendet habe, das nur nebenbei) und das hab ich dann intern einfach ausprobiert und es hat funktioniert (konkret war das irgendein Beispielskript für irgendein unnötiges Chatprogramm, aber egal, es ging ja ums Prinzip). Ich hab das dann nicht weiter verfolgt, weil wir dann im RL wieder Tarockieren konnten, aber es hätte funktioniert.

            Normalerweise trennt ein Webserver die Daten zweier Clients sehr strikt (zumeist durch konsequentes Wegwerfen nach einem Request), aber für einen Mediator mit WS-Technik musst Du ja eine Instanz haben, die sämtliche Clients kennt und ihre WS-Verbindungen aufrecht erhält.

            Du sprichst eine große Wahrheit gelassen aus. Vielleicht bringt ja der Link auf das Skript (hab ich gerade wiedergefunden😉) etwas Licht in die Angelegenheit...

            1. Hallo klawischnigg,

              nee, is klar.

              define('HOST_NAME',"localhost"); 
              define('PORT',"8090");
              // ...
              $socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
              socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1);
              socket_bind($socketResource, 0, PORT);
              socket_listen($socketResource);
              
              while (true) {
                // ...
              	foreach (...) {	
              		while(...) {
                    // ...
              			break 2;
              		}
                }
              }
              socket_close($socketResource);
              

              Mit diesem Script wird kein Indianer glücklich. Spätestens nach dem eingestellten Request-Timeout wird er sein Unglück mit der Axt über das Script ergießen und es ermorden.

              Das ist PHP für die Shell, es enthält eine Endlosschleife ohne Ausgang. Den Socketserver hast Du sicherlich von der Kommandozeile aus gestartet und mit Strg+C oder anderen Brutalomaßnahmen beendet. Denn einen regulären Ausgang aus dem while(true) gips nich, der socket_close findet nie statt. Oder ich hab zu flüchtig geguckt und einen anderen break übersehen...

              Der Client ist eine HTML Seite die ws://localhost:8090 anspricht. Serverseitig wurde das WS-Protokoll "von Hand" implementiert, ohne Library, ich bin überrascht, dass das so einfach geht.

              Rolf

              --
              sumpsi - posui - obstruxi
              1. Hi there,

                nee, is klar.

                Mit diesem Script wird kein Indianer glücklich. Spätestens nach dem eingestellten Request-Timeout wird er sein Unglück mit der Axt über das Script ergießen und es ermorden.

                so, jetzt hast Du sowohl meinen Widerspruchsgeist als auch mein Interesse geweckt. Ich werd' mir das jetzt einmal im Detail anschauen, was das wirklich macht und meld' mich dann wieder...😉

      2. Hallo Felix,

        jein. Der Apache kann wohl keinen Dienst hosten der Websockets anbietet, das ist richtig. Aber als ich mich anlässlich dieses Threads über Apache und WS informiert habe, habe ich ein Proxy-Modul gefunden, das WS fähig ist. Damit kann man erreichen, dass die WS Kommunikation an den weitergeleitet wird, der's kann, zum Beispiel einen Java-Kater oder einen gesockelten Knoten (es gibt auch andere Libs).

        Auf diese Weise kann man - wenn ich das richtig verstehe - den statischen bzw. "normalen" Teil des Web im Apache hosten und den WS-Service über die gleiche Adresse laufen lassen.

        Rolf

        --
        sumpsi - posui - obstruxi