6. Dynamisches Verhalten im Browser und im Server

Demo. Hier sind zwei Chat-Server.

  1. Völlig server-seitig. Klicken Sie auf http://193.174.103.62:2007/ da ein Server laufen sollte (wahrscheinlich nur während der Vorlesungs und Übung); den Source-Code finden Sie .
  2. http://193.174.103.62:6004/, Server schickt nur Daten, Browser fordert regelmäßig Updates.

In Kapitel 4 haben wir kleine Anwendungen geschrieben, in denen der Server dynamisch HTML-Seiten generiert und sie an den Browser schickt. Der Browser war ziemlich statisch; das einzige "dynamische" Element war die Funktionalität, auf HTML-Formulare zu reagieren und ihren Inhalt als GET- oder POST-Request an den Server zu schicken, so wie diese Abbildung es illustriert hat:

Daraufhin obliegt es dem Server, die Daten auszulesen und aus ihnen wiederum eine sinnvolle Webseite zu bauen. Als Beispiel gibt es hier diesen kleinen Chat-Server. Falls der Server laufen sollte (geht nur, wenn ich ihn starte), klicken Sie auf http://193.174.103.62:2007/ Ansonsten alden Sie die Quellcodedatei exercise-2007-forum.zip herunter. Dekomprimieren Sie sie, starten den Server via node message-board-server.js und gehen im Browser auf localhost:2007. Einige Anmerkungen:

  • Es gibt keine index.html inder Anwendung. Wenn Sie localhost:2007/index.html bzw. http://193.174.103.62:2007/index.html im Browser aufrufen, lädt dieser zwar brav eine index.html. Diese entspricht aber nicht einer wirklichen Datei, die auf dem Server liegt, sondern wird vom Server als String zusammengebaut (siehe den Html-Code als Strings in den Zeilen 40-72 im Quellcode message-board-server.js des Servers). Für den Browser ist das natürlich irrelevant. In beiden Fällen (echte Datei versus zusammengebauter String) erreicht es den Browser als String im Http Response.
  • Die index.html, die dem Browser geschickt wird, hängt vom Inhalt des Pinboards ab; je mehr Nachrichten geschrieben worden sind, desto länger wird sie.
  • Der Quelltext der index.html ist statisch bis auf das <form>-Element, mit dem der User einen neuen Beitrag schicken kann:
        <form action="submit-message" method="POST">
        <div class="form-group">
        <label for="username">Benutzername:</label>
        <input name="username" value=""><br>
        <textarea name="messageContent"></textarea>
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
Die ganze Logik wird also serverseitig ausgeführt, der Browser ist fast ausschließlich ein passives Werkzeug zum Anzeigen der Html-Seite. Dies hat mehrere Nachteile:
  • Der Nutzer wird nicht über neue Nachrichten informiert. Er muss erst die Seite neu laden.
  • Es wird jedes Mal eine frische Html-Seite generiert, auch wenn diese sich nur minimal von der letzten Version unterscheidet (weil beispielsweise nur ein Beitrag hinzugekommen ist).

In Kapitel 5 haben wir gesehen, dass ein Browser nicht nur Html darstellen kann, sondern mithilfe von Javascript eine Turing-vollständige Programmiersprache ausführen kann. Allerdings war alles in Kapitel 5 offline, es gab keine Interaktion it dem Server. In diesem Kapitel werden wir beide Paradigmen zusammenführen und Anwendungen programmieren, bei denen einerseits im Browser dynamisches Verhalten stattfindet (via Javascript), andererseits auch mit einem Server kommuniziert wird. Für die obige Chat-Applikation könnte das konkret heißen:

  • Der Browser schickt jede Sekunde einen GET-Request /anything-new/ an den Server.
  • Der Server baut nicht jedes mal die ganze Seite neu, sondern schickt nur eine Liste der neuen Nachrichten (die dann auch oft einfach leer ist).
Die Vorteile sind offensichtlich:
  • Das Netzwerk wird entlastet: es werden nur die nötigsten Daten geschickt; der Browser baut aus diesen dann die Html-Seite selbst zusammen.
  • Der Server wird entlastet. In der Praxis steht der Server häufig unter großer Last, während der Client-Rechner der Nutzer zum Großteil idle sein. Die paar Millisekunden, die es braucht, um aus den Daten (hier: Chat-Nachrichten) eine Html-Seite zu bauen, fallen für den Nutzer nicht ins Gewicht; für den Server jedoch in Summe sehr wohl.
  • Bei komplexeren Anwendungen (die beispielsweise das Ausfüllen mehrseitiger Formulare), kann ein Großteil der Logik bereits auf Client-Seite stattfinden (beispielsweise die Konsistenz der Daten überprüfen; dass alles vollständig ausgefüllt worden ist) und benötigt keinerlei Kommunikation mit dem Server (die ja auch immer mit Zeitverzögerung einhergeht).
Als Beispielapplikation habe ich wiederum einen kleinen Chatraum geschrieben. Klicken Sie auf http://193.174.103.62:6004/, falls der Server läuft, oder laden Sie sich 04-chatboard.zip herunter, starten node chatboard-server.js und gehen im Browser auf localhost:6004/. Das browser-seitige Javascript müssen sie noch nicht verstehen. Beachten Sie allerdings, wie extrem knapp die Logik auf Serverseite ist:
app.post("/submit-message", function (req, res) {
    messages.push(req.body); // add the message to the list of messages 
    res.status(200);
    res.send();
});

app.get("/refresh-messages", function (req, res) {  
  res.status(200);
  res.send(JSON.stringify(messages)); // convert the array 'messages' into a string and send it
});

Wir könnten die Anwendung noch effizienter machen, indem der Server bei jedem GET-Request nur die neuen Nachrichten schickt. Hierzu könnten der Server jeder Nachricht eine ID zuweisen (angefangen bei 0). Der Browser teilt dann in dem GET-Request dem Server mit, bis wohin er dann bereits Nachrichten empfangen hat, also beispielsweise /refresh-messages?start-at=369, worauf der Server dann mit der Liste aller Nachrichten ab 369 antwortet. Für edit- oder delete-Funktionen würde die serverseitige und clientseitige Logik dann noch komplexer werden.