Node.js | Eine Einführung für Anfänger, Teil 2

Tjark Rasche
Vom 28. August 2014

Nach einer recht langen Pause geht es heute mit der Serie über Node.js für Anfänger weiter. Nachdem ich dir im ersten Teil anhand eines sehr rudimentären Beispiels die Grundlagen von Node.js etwas näher gebracht habe, geht es heute etwas mehr ins Eingemachte.

Dieser Artikel wurde zuletzt vor über einem Jahr aktualisiert. Die Inhalte könnten inzwischen nicht mehr aktuell sein.

Am Ende dieses Artikels kannst du einen gut funktionierenden Webserver in Javascript schreiben der statische Dateien zuverlässig ausliefert und nette Error 404 Meldungen ausgeben kann, hierfür kommt das connect Modul als Teil des Express Frameworks zum Einsatz.

Doch zuerst müssen wie so oft noch einige Fragen beantwortet werden:

Was genau macht ein Webserver eigentlich?

Das ist eine Frage auf der vor allem viele Anfänger, aber auch manche Fortgeschrittene gar keine so genaue Antwort kennen. Das ist auch kein Wunder, da bei der normalen Webentwicklung mit PHP und HTML der Webserver tatsächlich schnell in den Hintergrund rückt, schließlich ist er bei so gut wie jedem Hosting Paket bereits vorinstalliert und voll einsatzbereit, weshalb der Entwickler von seiner Anwesenheit meist gar nichts bemerkt. Dennoch ist er Elementar, ohne ihn würde keine Website funktionieren.

Ein Webserver ist im Grunde genommen die Software die dafür sorgt dass Dateien über das Internet erreichbar ist. Sie läuft durchgehend auf dem Server und 'lauscht' nach Anfragen eines Browsers an den Server. Wenn ein Browser eine Anfrage stellt sorgt der Webserver dafür, dass die Datei die vom Browser angefordert wurde auch zum Browser gelangt und packt die entsprechenden Daten in die Antwort.

Dabei ist der Webserver sowohl für das sog. Routing verantwortlich, als auch für die Verarbeitung der HTTP-Anfragen. Beim Routing sorgt der Webserver dafür dass überhaupt die richtigen Dateien geliefert werden. Bspw. zeigt die Domain netzleben.com eigentlich direkt auf den Server von meinem Kollegen Florian. Logischerweise befindet sich dessen Wordpress-Installation aber nicht im Rootverzeichnis seines Servers, sondern irgendwo in den Unterverzeichnissen versteckt.

Der Webserver kümmert sich darum dass eben eine Anfrage des Browsers auf den Ordner zeigt in dem Wordpress installiert ist, und nicht auf das Stammverzeichnis. Um dieses Routing muss man sich bei der Entwicklung von Node.js-Apps selber kümmern, was aber eher ein Vorteil als ein Nachteil ist, und auch tatsächlich relativ leicht von der Hand geht. In diesem Beispiel verwende ich das Express Framework, dessen Bestandteil das im vorigen Artikel verwendete connect Modul ist. Im ersten Teil habe ich der Einfachheit halber lediglich connect verwendet. Die Umstellung ist allerdings nicht schwer, da die Syntax der Funktionen die im letzten Teil verwendet wurden bei Express die gleiche ist.

Die Verzeichnisstruktur bleibt die gleiche wie bei letzten Artikel:

  • nodeapp

    • client

    • server

      • server.js

Ich gehe davon aus dass du das erste Tutorial dieser Serie bereits gelesen hast und das Beispiel aus diesem bereits ausprobiert hast. Falls das nicht der Fall sein sollte kannst du einfach den ersten Artikel kurz überfliegen und die Schritte verfolgen. Das Beispiel an sich brauchst du nicht unbedingt umzusetzen, auch die Installation des connect Moduls ist für diesen Artikel nicht zwingend nötig. Jetzt musst du dich noch in der Shell in das nodeapp-Verzeichnis hangeln und dort mithilfe des Node Package Managers das express Framework installieren.

Auf meinem Uberspace sieht das ganze wie folgt aus:

[ogama@dorado ~]$ cd html/server 
[ogama@dorado server]$ npm install express

Beachte dass die Verzeichnisstruktur bei dir anders aussehen kann und du den cd Befehl entsprechend abändern musst. Um die Übersicht zu behalten, habe ich dir noch einmal das Codebeispiel vom ersten Artikel mithilfe von Express statt connect umgesetzt:

var express = require('express'); 
var app = express(); 
var server = app.use(function(req, res) { 
    res.send('hello world'); 
}); 
app.listen(64163);

Wie bereits vorhin angerissen, ist der Unterschied nicht sonderlich groß. Im Grunde besteht er bloß aus dem Ersetzen von connect() durch express(). Zusätzlich habe ich den Aufruf von express() noch in der Variable app untergebracht. Die Funktionsweise bleibt die gleiche, ebenso wie die Fuktionsaufrufe und alles andere. Ist dieser Schritt getan kann es auch schon ans Webserver-Programmieren gehen.

Einen Webserver Programmieren

Zu Beginn unseres Programms müssen wir Express erstmal mit var express = require('express'); var app = express(); in unser Programm einbinden und starten. Express steht uns nun immer in var app zur Verfügung.

Middleware verwenden

Um nun statische Dateien mithilfe von Express auszuliefern, eignet sich am besten eine sog. Middleware. Middlewares sind Funktionen, die bereits vor dem eigentlichen Handling des http-Requests von Express aufgerufen werden. In Express verwendet man sie mit app.use(funktionsaufruf)

var express = require('express'); 
var app = express(); 
app.use('/', express.static(__dirname)); 
app.get('/*', function(req, res) { 
    res.status(404).sendfile(__dirname + '/error.html'); 
}); 
app.listen(64163);

Im oberen Beispielcode kommt die einzige von Express selber mitgelieferte Middleware zum Einsatz: express.static(). Dem Namen nach kannst du dir wahrscheinlich schon denken was sie macht, nämlich statische Dateien ausliefern. Dafür braucht sie als Funktions-Parameter lediglich das Verzeichnis das als Stammverzeichnis hierfür verwendet werden soll. In unserem Fall sollen die Dateien aus dem gleichen Verzeichnis stammen wie die Datei in der die Middleware aufgerufen wird, weshalb der Platzhalter __dirname reicht, welcher immer dem aktuellem Verzeichnis entspricht. Den Rest erledigt sie von selbst. Um das eigentliche Ausliefern der Dateien brauchen wir uns also nicht mehr zu kümmern.

Middlewares werden in Express nacheinander abgearbeitet, wobei die Reihenfolge im Code der in der Ausführung entspricht. Nach den Middlewares, kommt wie oben bereits angedeutet das eigentliche Handling des http-Requests. Das geschieht in unserem Beispiel mit folgendem Code:

app.get('/*', function(req, res) { 
    res.sendfile(__dirname + '/error.html'); 
});

Er ist relativ selbsterklärend. Bei allen Adressen die aufgerufen werden wird eine 404-Fehlermeldung und immer die gleiche Datei ausgeliefert, nämlich error.html, welche eine kleine Error 404 Nachricht enthält.

Die Methode app.get() verlangt als Parameter eine Route (das ist im Grunde genommen der Teil einer URL der hinter der eigentlichen Domain kommt) und eine Funktion die ausgeführt werden soll, wenn die angegebene Route aufgerufen wird. In unserem Beispiel wird also egal welche Route aufgerufen wird (bspw. domain.tld/bla, oder domain.tld/blub) die gleiche Datei ausgeliefert.

Aber warum das ganze? Eigentlich macht es doch keinen Sinn immer eine HTML-Datei mit einer 404 Fehlermeldung auszuliefern, oder?

Richtig, das macht keinen Sinn. Allerdings wird auch nur dann eine Fehlermeldung ausgeliefert, wenn express.static() keine statische Datei zum Ausliefern gefunden hat, denn dann ruft sie die berühmt-berüchtigte Funktion next auf, welche nichts anderes tut, als zur nächsten auszuführenden Middleware zu springen. Da es in unserem Beispiel keine andere Middleware gibt, wird direkt dazu übergegangen die app.get() Aufrufe abzuarbeiten, und somit eine 404-Fehlermeldung und die HTML-Datei mit der Fehlermeldung an den Browser zu senden. Eigentlich gar nicht so kompliziert oder?

Doch was macht man jetzt wenn man vor dem Ausliefern einer Datei noch etwas Javascript-Code ausführen möchte?

Das ist Beispielsweise nötig wenn du Seiten dynamisch generieren möchte, oder einfach nur einen kleinen Logger einbauen möchtest. Beides kannst du mit den bis jetzt besprochenen Mitteln ganz einfach umsetzen. Zuerst den Logger, denn der funktioniert als einfache Middleware:

var express = require('express'); 
var app = express(); 
app.use(function(req, res, next){ 
    console.log(req.url); next(); 
}); 
app.use('/', express.static(__dirname)); 
app.get('/*', function(req, res) { 
    es.status(404).sendfile(__dirname + '/error.html'); 
}); 
app.listen(64163);

Ein sehr einfaches Beispiel. Eine anonyme Funktion wird direkt in app.get() erstellt und führt einen einfachen console.log() befehl aus, mit dem die aufgerufene URL in der Konsole geloggt wird. Mit dem Aufruf von next() am Ende wird die nächste Middleware gestartet, und liefert wie gewohnt statische Dateien aus.

Um vor dem Ausliefern von Dateien noch eigenen Code auszuführen, kannst du einfach einen weiteren Router vor unserer 404-Fehlermeldung registrieren:

var express = require('express');
var app = express();

app.use(function (req, res, next) {
	console.log(req.url);
	next();
});

app.use('/', express.static(__dirname));
app.get('/speziell', function (req, res) {
	console.log('Eine Spezielle Datei wird ausgeliefert!');
	res.sendfile(__dirname + '/speziell.html');
});

app.get('/*', function (req, res) {
	res.status(404).sendfile(__dirname + '/error.html');
});

app.listen(64163);

In diesem einfachem Beispiel wird beim Aufruf von domain.tld:64163/speziell erst die Nachricht 'Eine Spezielle Datei wird ausgeliefert!' geloggt und dann die Datei speziell.html an den Browser gesendet.

Natürlich könnte man hier statt console.log() weitaus komplexere Abläufe programmieren, und selbstverständlich müsste man am Ende nicht unbedingt eine statische Datei ausliefern, sondern könnte auch eine dynamisch generieren. Aber dazu kommen wir im nächsten Teil der Reihe :) Falls du noch Fragen hast, schreibe einfach einen Kommentar und ich helfe dir soweit wie es geht. Die Dateien aus dem Tutorial kannst du hier herunterladen.

Was dich in den nächsten Teilen erwartet:

  • Dynamisch Seiten generieren mit Express und einer Templating Engine

  • Immer noch eine Einführung in das Modul socket.io

  • Eine einfache Anwendung die das gelernte zusammenfasst

  • # node.js
  • # Uberspace
  • # Webentwicklung

Du suchst die Kommentare?

Keine Sorge, die sind nicht verloren! Es dauert aber noch eine Weile, bis sie wieder zu sehen sind und du neue Kommentare hinterlassen kannst.

Netzleben ist frisch von einer alten Kirby-Website auf eine neue, Statamic-basierte Website umgezogen. Leider ist das Plugin für Kommentare mit Statamic 3 noch nicht kompatibel.