mitmario.dev

Statische Dateien

Node.js Sandbox 3 Min Lesezeit 3 BeispieleLektion 5 von 7

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

Ein Ordner statt vieler Routen
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.html als Standard für ein Verzeichnis. Deshalb beantwortet der Server oben auch /, obwohl niemand eine Route dafür angelegt hat.
  • Unterordner, wie /api/status.json zeigt.
  • 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

Der relative Pfad ist eine Falle
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

Was im Ordner liegt, ist öffentlich
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, kostenlos

Zu 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.