express.static ist die eingebaute Middleware, die Dateien aus einem Ordner ausliefert. app.use(express.static(path.join(__dirname, 'public'))) macht jede Datei in public unter demselben Pfad in der URL erreichbar: public/style.css beantwortet /style.css, und public/index.html beantwortet /. Express setzt den Content-Type anhand der Dateiendung, und wenn keine Datei passt, gibt es die Anfrage an deine Routen weiter, statt mit 404 zu antworten.
Die Antwort auf GET /style.css ist der Text der Datei, mit Content-Type: text/css; charset=utf-8 im Headers-Tab. Sende GET /, um index.html zu bekommen, dann GET /api/time: Eine solche Datei gibt es nicht, also antwortet die Route.
Warum der Ordnerpfad __dirname braucht
express.static('public') löst 'public' relativ zu dem Ordner auf, aus dem du Node gestartet hast, nicht zu dem Ordner, in dem server.js liegt. Das funktioniert, wenn du node server.js im Projekt ausführst, und bricht, wenn ein Prozessmanager oder ein Skript die App von woanders startet:
// project/server.js uses express.static('public')
// cd project && node server.js -> serves project/public
// node project/server.js -> looks for ./public, every file is 404
path.join(__dirname, 'public') ist der Ordner neben der Datei, die diese Zeile enthält, egal, wo Node gestartet wurde. In einem ES-Modul nimmst du path.join(import.meta.dirname, 'public') (ab Node 20.11). Die Seite zum path-Modul behandelt __dirname und path.join im Detail.
Dateien unter einem Präfix ausliefern
Übergib zuerst einen Einhängepfad, um den Ordner unter einem URL-Präfix auszuliefern. Das Präfix gehört nicht zum Pfad der Datei auf der Festplatte:
GET /assets/app.js liefert console.log("hi"); als text/javascript, und GET /assets/img/dot.svg greift in den Unterordner. Sende GET /app.js ohne Präfix: Das ist ein 404, weil die Dateien nur unter /assets existieren. Mit einem Präfix kollidieren Datei-URLs nicht mit deinen API-Routen.
Cache-Header mit maxAge
Standardmäßig sendet Express Cache-Control: public, max-age=0, Browser fragen also bei jeder Nutzung beim Server nach (und bekommen dank des ETag-Headers ein schnelles 304 Not Modified, wenn sich die Datei nicht geändert hat). Für Dateien, deren Namen sich bei jedem Build ändern, etwa app.3f9a1c.js, sag Browsern, dass sie sie behalten sollen:
Öffne den Headers-Tab: Cache-Control ist jetzt public, max-age=604800, sieben Tage in Sekunden. index: false schaltet das Ausliefern von index.html für Ordner-URLs ab. Weitere nützliche Optionen sind extensions: ['html'], womit /about die Datei about.html findet, und dotfiles, das standardmäßig 'ignore' ist, damit Dateien wie .env nie ausgeliefert werden.
Single Page Apps: Fallback auf index.html
Eine React- oder Vue-App mit Client-seitigem Routing braucht für jeden unbekannten Pfad index.html, damit ein Neuladen auf /settings keinen 404 ergibt. Setz den Fallback hinter express.static und deine API-Routen:
app.use(express.static(path.join(__dirname, 'dist')));
app.use('/api', apiRouter);
// Express 5 wildcard syntax
app.get('/*splat', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
Häufige Fehler
Den Ordnernamen in die URL schreiben. Mit app.use(express.static('public')) ist die URL /style.css, nicht /public/style.css. Wenn du /public in der URL willst, häng es ein: app.use('/public', express.static(...)).
Dateien in HTML mit relativen Pfaden verlinken. <link href="style.css"> auf der Seite /blog/post fragt nach /blog/style.css. Beginn den Pfad mit einem Schrägstrich: /style.css.
Geheimnisse in den static-Ordner legen. Alles darin ist öffentlich. Halte Konfigurationsdateien, Schlüssel und Quellcode da raus.
Häufig gestellte Fragen
Kann ich express.static mehrmals verwenden?
Ja. Registrier eines pro Ordner; Express sucht in der Reihenfolge, in der du sie hinzugefügt hast, und liefert die erste gefundene Datei aus. Gib jedem einen eigenen Einhängepfad, wenn die Ordner Dateien mit gleichem Namen enthalten könnten.
Sollte Express in Produktion statische Dateien ausliefern?
Für kleine Apps ist das in Ordnung. Bei viel Traffic stell ein CDN oder einen Reverse Proxy wie Nginx davor, der Dateien schneller ausliefert und näher an den Nutzern cacht, und nutz Express für die API.
Wie sende ich aus einer Route eine bestimmte Datei?
Mit res.sendFile(path.join(__dirname, 'files', 'report.pdf')). Der Pfad muss absolut sein (oder du übergibst eine root-Option). Nimm stattdessen res.download(), wenn der Browser die Datei speichern statt anzeigen soll.