Node.js/Chat mit WebSockets

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

In diesem Tutorial erstellen Sie eine Echtzeit-Chat-Anwendung mit mehreren Teilnehmern, die Nachrichten an einen Empfänger sofort und ohne Seitenaktualisierung selbstständig sendet und anzeigt. Dabei wird die Webseite aktualisiert, ohne dass eine Anfrage vom Client an den Server stattfinden muss. Der Einfachheit halber werden wir den Authentifizierungsteil vermeiden. Es soll auch nur einen Chatkanal geben.

Node.chat logo.svg

Wir verwenden dazu Node.js, WebSockets, sowie die Node-Bibliothek ws.

Planung des Datenprotokolls

Für eine verteilte Anwendung muss man festlegen, wie die Kommunikation zwischen Client und Server ablaufen soll - das Protokoll. Dazu muss man sich überlegen, welche Interaktionen Client und Server benötigen, und welche Daten dafür erforderlich sind.

Die eigentliche Verbindungsaufnahme ist Teil des WebSocket-Protokolls und benötigt keine eigenen Nachrichten. Sobald die physische WebSocket-Verbindung steht, sollte sich der Server aber beim Client melden und eine Begrüßungsnachricht ausgeben. Wenn der Client diese Nachricht empfängt, weiß er, dass der Server kommunikationsfähig ist, und kann den Benutzer am Server eintragen. Der Server sollte daraufhin allen bereits angemeldeten Chat-Benutzern den neuen Benutzer ankündigen, d.h. eine Benachrichtigung senden. Eine solche Benachrichtigung sollte sich von normalen Nachrichten unterscheiden.

Für den eigentlichen Chat-Betrieb sollte ein Benutzer zumindest Nachrichten an alle Teilnehmer senden können. Die Möglichkeit, Nachrichten gezielt an einzelne Teilnehmer zu schicken, ist ebenfalls denkbar, aber für einen Basis-Chatserver nicht erforderlich. Chat-Nachrichten eines Benutzers müssen dann vom Server an die übrigen Teilnehmer verteilt werden. Ob der Absender der Nachricht seine eigene Nachricht ebenfalls erhält (Echo), ist etwas, das man beliebig festlegen kann. Mit Echo muss der Client sich nicht darum kümmern, gesendete Nachrichten in die Chatkanal-Anzeige einzufügen, das wird vom Server-Echo automatisch übernommen. Der Client erhält auf diese Weise auch das klare Signal, dass seine Nachricht angekommen ist. Dafür müssen aber mehr Daten übertragen werden und bis das Echo da ist, vergeht Zeit. Wenn der Server kein Echo schickt, entfällt diese Datenübertragung und die Wartezeit. Diese Überlegung ist aber seit Ablösung der analogen Modems nicht mehr relevant, wir werden daher einen Server mit Echo bauen.

Wir werden also die folgenden Nachrichten austauschen. Die Übertragungsrichtung "up" bedeutet: zum Server, und "down": zum Client. Das technische Nachrichtenformat sollen JavaScript-Objekte sein, die im JSON-Format übermittelt werden. Jedes dieser Objekte wird eine Eigenschaft type enthalten und dazu nach Bedarf weitere Eigenschaften, je nach Typ. Die nachstehende Tabelle fasst es zusammen.

type Richtung Inhalt
hello down message: Begrüßungsnachricht vom Server
connect up username: Aliasname des Benutzers
connected down message: Bestätigungsmeldung

channels: Array mit verfügbaren Chat-Kanälen. Minimum: [ 'default' ]

notify down message: Allg. Benachrichtigung des Servers an den Client
monitor up channel: Channel, dessen Nachrichten man empfangen möchte
monitoring down channel: Bestätigung, dass der Empfang auf diesem Channel aktiv ist

users: Array mit allen Usern, die in diesem Kanal auf Empfang sind
messages: Zwischengespeicherte Messages auf diesem Kanal

post up message: Nachricht, die der Client in den Chatkanal schreiben möchte
posted down sender: Aliasname des Absenders

color: Farbe, in der die Nachricht anzuzeigen ist
message: Nachricht, in den Chatkanal geschrieben wurde.

Ob diese Sammlung an Nachrichten vollständig und 100% brauchbar ist, weiß man in der Planungsphase oft nicht. Wir werden mit diesem Kommunikationsprotokoll beginnen und es, sofern nötig, anpassen.

Frontend

Wir können damit beginnen, ein neues Projektverzeichnis zu erstellen und in dieses zu wechseln. Der Client soll schlank gehalten werden, aber ein paar Funktionen sind doch erforderlich.

HTML-Markup

Der Chat läuft auf einer kleinen Webseite, auf der Benutzer ihren Namen eingeben können.

Chat Client, Grundgerüst
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat mit WebSockets</title>
    <link rel="stylesheet" href="chat.css">
    <script type="module">
      import { ChatController } from "./chat-client.js";
      const chat = new ChatController( {
          controlBox: document.querySelector("#info"),
          chatOutput: document.querySelector("#chatoutput")
      });
    </script>
  </head>
  <body>
    <h1>Chat mit WebSockets</h1>
    <form id="connector">
      <button class="connect" type="submit">Verbinden</button>
      <button class="disconnect"  type="button">Trennen</button>
      <label for="chatserver">URL zum Chatserver</label><br>
      <input name="url" id="chatserver" type="text" required pattern="wss?:\/\/.*"><br>
      <label for="youralias">Ihr Name im Chat</label><br>
      <input name="alias" id="youralias" type="text" required>
    </form>
    <main id="chatoutput">
    </main>
  </body>
</html>

Dieses HTML soll später noch verfeinert werden. Zunächst einmal haben wir "nur" eine Überschrift, ein Formular für die Verbindungsdaten und ein main Element. Im main-Element sollen später die empfangenen Nachrichten gesammelt werden.

Backend

Der große Vorteil von WebSockets ist die Zwei-Wege-Kommunikation. Ein Benutzer sendet eine Nachricht (Client →Server), die der Server an alle angeschlossenen Benutzer weitergibt (Server → Client).

Für die Client → Server-Kommunikation reicht Plain text. Aber für Server → Client ist es ein bisschen komplexer. Wir müssen zwischen 3 verschiedenen Arten von Nachrichten unterscheiden:

  • Server ordnet dem Benutzer eine Farbe zu
  • Server sendet gesamten Nachrichtenverlauf
  • Server sendet eine Nachricht an alle Benutzer

Daher ist jede Nachricht ein einfaches JavaScript-Objekt, das in JSON kodiert ist.

WebSockets

Die WebSocket API ermöglicht es, eine dauerhafte Verbindung zwischen Webanwendung und Server aufzubauen, bei der Sie Nachrichten zum Server senden und ereignisorientierte Antworten erhalten können, ohne beim Server die Antwort abfragen zu müssen. Gegenüber dem langsameren HTTP-Protokoll, das nach dem Senden einer Anfrage immer auf Antworten warten muss, werden auch keine Header-Felder benötigt, was ebenfalls die Datenübertragung beschleunigt.

ToDo (weitere ToDos)

wird fortgesetzt


Weblinks

WebSockets