Back

Wie Middleware in Node.js funktioniert

Wie Middleware in Node.js funktioniert

Sie haben app.use() überall in Express-Codebasen gesehen. Sie wissen, dass Middleware zwischen Requests und Responses sitzt. Aber wenn etwas in dieser Kette kaputt geht – ein Request hängt, ein Fehler verschwindet oder Handler in der falschen Reihenfolge ausgeführt werden – bricht das mentale Modell zusammen.

Dieser Artikel erklärt, wie Node.js-Middleware tatsächlich funktioniert: was sie ist, wie die Kontrolle durch die Kette fließt und was sich in Express 5 geändert hat.

Wichtigste Erkenntnisse

  • Middleware ist ein Framework-Pattern, kein Node.js-Feature – Express implementiert es auf Basis des Core-Moduls http
  • Die Ausführungsreihenfolge ist entscheidend: Middleware wird in Registrierungsreihenfolge ausgeführt, und Error-Handler müssen am Ende stehen
  • Die Funktion next() steuert den Ablauf; wird sie ohne Response übersprungen, hängt der Request
  • Express 5 fängt abgelehnte Promises von async Middleware und Route-Handlern nativ ab, wodurch manuelle Wrapper überflüssig werden

Middleware ist ein Framework-Pattern, kein Node.js-Feature

Node.js selbst kennt kein Middleware-Konzept. Das Core-Modul http gibt Ihnen ein Request- und Response-Objekt – nicht mehr. Middleware ist ein Pattern, das Frameworks wie Express auf Node.js aufsetzen.

Express-Middleware folgt einer spezifischen Struktur: Funktionen, die req, res und next erhalten. Das Framework verwaltet einen Stack dieser Funktionen und ruft sie sequenziell für jeden eingehenden Request auf. Dieser Request-Lifecycle in Node.js-Frameworks verleiht Middleware ihre Stärke.

Andere Frameworks implementieren ähnliche Patterns unterschiedlich. Koa verwendet ein „Zwiebel-Modell”, bei dem Middleware nachfolgende Handler umschließt. Fastify nutzt Hooks an bestimmten Lifecycle-Punkten. Das Konzept ist übertragbar, die Semantik jedoch nicht.

Der Request-Response-Lifecycle

Wenn ein Request eine Express-Anwendung erreicht, tritt er in eine Pipeline ein:

  1. Express gleicht den Request mit registrierter Middleware und Routes ab
  2. Jede Middleware-Funktion wird in Registrierungsreihenfolge ausgeführt
  3. Die Kontrolle wird über next() weitergegeben oder stoppt, wenn eine Response gesendet wird
  4. Error-Handling-Middleware fängt Fehler ab, die an next(err) übergeben werden, sowie Fehler, die innerhalb von Express-verwalteter Middleware und Route-Handlern geworfen oder rejected werden

Die Funktion next() ist der Mechanismus, der die Kontrolle durch die Kette bewegt. Rufen Sie sie auf, und Express führt die nächste passende Middleware aus. Überspringen Sie sie, ohne eine Response zu senden, hängt der Request unbegrenzt.

Die Reihenfolge der Middleware ist entscheidend

Express-Middleware wird in der Reihenfolge ausgeführt, in der Sie sie registrieren. Das ist nicht nur ein Detail – es ist die Grundlage von Middleware-Patterns in Node.js.

app.use(parseBody)
app.use(authenticate)
app.use(authorize)
app.get('/data', handler)

Hier wird parseBody zuerst ausgeführt und stellt Request-Daten für authenticate bereit. Vertauschen Sie die Reihenfolge, und die Authentifizierung schlägt fehl, weil der Body noch nicht geparst wurde.

Diese Reihenfolge betrifft auch das Error-Handling. Error-Handling-Middleware muss nach den Routes stehen, die sie schützt.

Kurzschluss der Response

Middleware kann den Request-Response-Zyklus vorzeitig beenden, indem sie eine Response sendet, ohne next() aufzurufen. So lehnt Authentifizierungs-Middleware nicht autorisierte Requests ab:

function requireAuth(req, res, next) {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  next()
}

Sobald res.send(), res.json() oder ähnliche Methoden ausgeführt werden, wird nachfolgende Middleware für diesen Request nicht mehr ausgeführt. Dieser Kurzschluss ist beabsichtigt und nützlich.

App-Level-, Router-Level- und Route-Level-Middleware

Express-Middleware wird auf verschiedenen Ebenen angehängt:

App-Level-Middleware wird für jeden Request an die Anwendung ausgeführt. Verwenden Sie app.use() für übergreifende Belange wie Logging oder Body-Parsing.

Router-Level-Middleware wird für Requests ausgeführt, die einem bestimmten Router entsprechen. Dies begrenzt Middleware auf Route-Gruppen, ohne die gesamte Anwendung zu beeinflussen.

Route-Level-Middleware wird nur für bestimmte Routes ausgeführt. Übergeben Sie Middleware-Funktionen direkt an Route-Definitionen für gezieltes Verhalten wie Validierung.

Der Unterschied liegt im Scope, nicht in der Fähigkeit. Alle drei verwenden dieselbe Funktionssignatur.

Error-Handling und Express 5 Middleware

Express identifiziert Error-Handling-Middleware an ihrer Vier-Parameter-Signatur: (err, req, res, next). Wenn eine Middleware next(err) aufruft oder einen Fehler wirft, überspringt Express reguläre Middleware und springt zu Error-Handlern.

Express 5 ändert, wie async Fehler funktionieren. In Express 4 erforderten abgelehnte Promises und async Exceptions manuelles Handling oder Third-Party-Wrapper. Express 5 fängt abgelehnte Promises von async Funktionen nativ ab und leitet sie automatisch an Error-Handler weiter.

// Express 5: kein Wrapper nötig
app.get('/data', async (req, res) => {
  const data = await fetchData() // Rejection triggert Error-Middleware
  res.json(data)
})

app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message })
})

Error-Handling-Middleware muss dennoch zuletzt registriert werden, nach Routes und anderer Middleware.

Fazit

Middleware ist ein Framework-Level-Pattern zur Verarbeitung von Requests durch eine Kette von Funktionen. Das Verständnis der Ausführungsreihenfolge, der Rolle von next() und der Platzierung von Error-Handlern beseitigt die meisten Middleware-Debugging-Probleme.

Das native async Error-Handling von Express 5 beseitigt einen häufigen Schmerzpunkt, aber die Grundlagen bleiben: Registrieren Sie Middleware in der richtigen Reihenfolge, rufen Sie next() auf oder senden Sie eine Response, und platzieren Sie Error-Handler am Ende.

FAQs

Wenn Sie vergessen, next() aufzurufen und keine Response senden, hängt der Request unbegrenzt. Express wartet entweder darauf, dass next() aufgerufen wird, um die Kette fortzusetzen, oder dass eine Response an den Client gesendet wird. Stellen Sie immer sicher, dass Ihre Middleware entweder next() aufruft, um die Kontrolle weiterzugeben, oder eine Response sendet, um den Zyklus zu beenden.

Ja, aber Sie müssen Fehler manuell behandeln. Express 4 fängt abgelehnte Promises nicht automatisch ab, sodass unbehandelte Rejections Ihre Error-Handling-Middleware nicht triggern. Umschließen Sie async Code mit try-catch-Blöcken oder verwenden Sie eine Wrapper-Funktion, die Fehler an next() weiterleitet. Express 5 macht diese Anforderung überflüssig, indem es Rejections nativ abfängt.

Error-Handling-Middleware benötigt exakt vier Parameter: err, req, res und next. Wenn Sie einen Parameter weglassen, behandelt Express sie als reguläre Middleware und überspringt sie beim Error-Handling. Überprüfen Sie auch, dass Ihr Error-Handler nach allen Routes und anderer Middleware in Ihrer Anwendung registriert ist.

Beide registrieren Middleware mit derselben Funktionssignatur, unterscheiden sich aber im Scope. app.use() hängt Middleware auf Anwendungsebene an und wird für alle Requests ausgeführt. router.use() hängt Middleware an eine bestimmte Router-Instanz an und wird nur für Requests ausgeführt, die dem gemounteten Pfad dieses Routers entsprechen.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay