Abschnitt 9 · Lektion 5
Statische Dateien
In Lektion 8.7 hast du gesehen, was es kostet, Dateien von Hand auszuliefern: eine Zuordnungstabelle für Inhaltstypen, eine Route je Datei, und für jede neue Datei wieder dasselbe.
Ein Aufruf
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Startseite</title>
<link rel="stylesheet" href="stil.css">
</head>
<body>
<h1>Startseite</h1>
<p><a href="/api/status.json">/api/status.json</a></p>
</body>
</html> body {
color: teal;
} { "status": "ok" } import express from "express";
const app = express();
// Ein Aufruf statt einer Route je Datei.
app.use(express.static("public"));
app.listen(3000); express.static(ordner) erzeugt eine Middleware, die für jede Anfrage nachsieht, ob im Ordner eine
passende Datei liegt. Wenn ja, schickt sie diese, sonst reicht sie weiter.
Was dabei mitkommt, ohne dass du es hinschreibst:
- Der Inhaltstyp, anhand der Endung. Genau die Tabelle aus 8.7, nur vollständig.
index.htmlals Standard für ein Verzeichnis. Deshalb beantwortet der Server oben auch/, obwohl niemand eine Route dafür angelegt hat.- Unterordner, wie
/api/status.jsonzeigt. - Zwischenspeicher-Kopfzeilen, damit ein Browser dieselbe Datei nicht bei jedem Aufruf neu holt.
Rechts steht die Startseite, und sie ist teal: Der Browser hat also auch das Stylesheet geholt, ohne dass jemand eine Route dafür geschrieben hat. Im Reiter „Netzwerk” siehst du beide Anfragen untereinander, die Seite und die Datei daneben. Der Link darunter führt zum JSON im Unterordner.
Ein wichtiger Nebeneffekt: Die Middleware reicht weiter, wenn sie nichts findet. Sie beendet also nicht die Kette, und deshalb kannst du eigene Routen daneben betreiben. Wo genau du sie hinschreibst, entscheidet allerdings, wer gewinnt, wenn beide auf dieselbe Adresse passen. Aus 9.2 weißt du die Regel: von oben nach unten, der erste gewinnt.
Wo der Ordner liegt
body {
color: teal;
} import express from "express";
import { join } from "node:path";
// Der Prozess laeuft absichtlich aus dem Verzeichnis darueber, so als
// haette jemand "node unterordner/server.js" aufgerufen.
process.chdir("..");
const app = express();
// Relativ zum Arbeitsverzeichnis. Das ist jetzt ein anderes, also
// findet der Server nichts mehr und /stil.css gibt 404.
app.use(express.static("public"));
// Tausch die Zeile darueber gegen diese und lade die Seite neu:
// app.use(express.static(join(import.meta.dirname, "public")));
app.listen(3000); express.static("public") ist relativ zum Arbeitsverzeichnis des Prozesses, nicht zur Datei, in
der es steht. Das ist dieselbe Regel wie bei den Dateipfaden aus Lektion 2.4, hier zum ersten Mal
mit ernsthaften Folgen.
Solange du node server.js im Projektordner startest, fällt beides zusammen und alles geht gut. Ruft
jemand node unterordner/server.js eine Ebene höher auf, oder startet ein Dienst dein Programm mit
einem anderen Arbeitsverzeichnis, liefert dein Server plötzlich nichts mehr aus. Und zwar ohne
Fehlermeldung, denn ein leerer Ordner ist für express.static kein Problem, sondern einfach ein
Ordner ohne Treffer.
Rechts kannst du es sehen: Dort steht die Fehlerseite von Express, obwohl public/stil.css direkt
daneben im Editor liegt. Ein Detail, das man wissen sollte, wenn man den Fehler sucht: Der Pfad
wird einmal beim Anlegen der Middleware aufgelöst, nicht bei jeder Anfrage. Es zählt also das
Arbeitsverzeichnis beim Start.
join(import.meta.dirname, "public") ist der sichere Weg. import.meta.dirname ist das Verzeichnis
der Datei, in der es steht, und damit unabhängig davon, von wo aus jemand startet. Die Zeile steht
im Beispiel auskommentiert darunter: Tausch sie gegen die andere, lade die Seite neu, und das
Stylesheet ist da.
Und jetzt der Teil, der wehtut
passwort=123 GEHEIM=123 import express from "express";
const app = express();
// Beide Dateien liegen in public, beide hat niemand verlinkt.
app.use(express.static("public"));
app.listen(3000); Was in diesem Ordner liegt, kann jeder abrufen. Nicht nur das, was du verlinkt hast. Es gibt kein Verzeichnis, das man kennen müsste, und keine Anmeldung. Wer den Dateinamen errät, bekommt die Datei.
sicherung.bak hat niemand verlinkt, niemand erwähnt, und trotzdem steht sie rechts vor dir, samt
Passwort. Das ist keine Lücke in Express, sondern genau das, was express.static verspricht.
Eine gute Nachricht steckt trotzdem darin: .env wird nicht ausgeliefert. Tipp /.env in die
Adresszeile, und es kommt eine 404.
express.static überspringt Dateien, deren Name mit einem Punkt beginnt, und das ist die Voreinstellung.
Verlass dich darauf trotzdem nicht als Sicherheitsmaßnahme, sondern nur als letztes Netz. Die
gefährlichen Dateien heißen nämlich meistens gar nicht .env, sondern sicherung.bak,
konfiguration.json, dump.sql oder notizen.txt.
Die Regel dazu ist unbequem, aber kurz: In den öffentlichen Ordner gehört nur, was öffentlich sein soll. Keine Konfigurationsdateien, keine Sicherungskopien, keine Datenbankauszüge, keine Zwischenstände. Wenn du dir bei einer Datei unsicher bist, gehört sie nicht hinein.
Abschnitt 15 kommt darauf zurück und schaut sich an, was passiert, wenn jemand gezielt danach sucht.
Zum Mitnehmen
Ein Aufruf liefert einen ganzen Ordner aus, samt Inhaltstypen und index.html. Und alles, was darin liegt, ist damit öffentlich.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.