In Express un middleware è una funzione con la firma (req, res, next) che viene eseguita tra l'arrivo di una richiesta e l'invio della risposta. Ogni middleware può leggere o modificare req e res, chiudere la richiesta inviando una risposta, o chiamare next() per passare la richiesta alla funzione successiva. app.use(fn) aggiunge un middleware per ogni richiesta, ed Express esegue tutto nell'ordine in cui l'hai registrato.
La Console mostra i tre passaggi in ordine per ogni richiesta, e la route legge req.startedAt, una proprietà aggiunta dal logger. Invia GET /missing: i due middleware scrivono comunque il log, perché app.use() corrisponde a ogni path, poi Express risponde 404 dato che nessuna route corrisponde.
Dimenticare next()
Un middleware che non invia una risposta e non chiama next() lascia la richiesta appesa. Il client aspetta fino al timeout e nei log non compare niente, per questo è un bug comune con i middleware. Cancella next(); dal logger qui sopra e invia di nuovo GET /: la richiesta non riceve mai risposta.
La regola è semplice: ogni percorso dentro un middleware finisce con esattamente una di queste cose:
next()per continuare,next(err)per saltare all'error handler (vedi la gestione degli errori in Express),- una risposta come
res.json()ores.status(401).send().
Anche chiamare next() dopo aver inviato una risposta è un bug. L'handler successivo prova a inviare una seconda risposta ed Express lancia ERR_HTTP_HEADERS_SENT. Scrivi return res.status(401).json(...) così la funzione si ferma lì.
Un controllo di accesso che ferma la richiesta
Un middleware che rifiuta una richiesta invia la risposta da solo e non chiama mai next(). Passalo come argomento in più a una route per proteggere solo quella:
La prima richiesta riceve 401 con {"error":"Missing or wrong API key"}. Aggiungi l'header x-api-key: secret123 nella barra della richiesta e inviala di nuovo: ora la risposta è {"users":42,"caller":"reporting-app"}. /public non esegue mai il controllo.
Dove viene eseguito un middleware
| Scrivi | Viene eseguito per |
|---|---|
app.use(fn) | Ogni richiesta, ogni metodo |
app.use('/api', fn) | I path che iniziano con /api |
app.get('/admin', fn, handler) | Solo GET /admin, prima di handler |
router.use(fn) | Ogni route di quel router |
L'ordine fa parte del significato. Un logger registrato dopo le route non scrive mai le richieste a cui quelle route hanno risposto, perché una route che invia una risposta non chiama next(). Registra prima i middleware globali come logging, parsing del body e CORS, poi le route, poi gli handler 404 e degli errori.
I middleware integrati
Express include alcuni middleware da aggiungere con app.use(). I body parser riempiono req.body; senza di loro è undefined.
| Middleware | Cosa fa |
|---|---|
express.json() | Fa il parsing dei body JSON (Content-Type: application/json) |
express.urlencoded() | Fa il parsing dei form HTML inviati (name=Ada&age=36) |
express.text() | Mette un body di testo semplice in req.body come stringa |
express.static('public') | Serve i file di una cartella |
Invia POST /echo con il body {"name": "Ada"} e la risposta contiene "body":{"name":"Ada"}. Togli la riga express.json(), inviala di nuovo, e body sparisce dalla risposta: req.body è undefined e JSON.stringify omette i valori undefined. Anche pacchetti come cors, helmet e morgan sono middleware: li installi con npm install e li passi ad app.use() nello stesso modo. La pagina su express.static spiega come servire file.
Errori comuni
Chiamare il middleware invece di passarlo. app.use(logger()) esegue logger una volta all'avvio e registra il suo valore di ritorno. Scrivi app.use(logger). (express.json() ha le parentesi perché restituisce una funzione middleware.)
Aggiungere il body parser dopo le route. Le route girano per prime e vedono req.body come undefined.
Aspettarsi che app.use('/admin', fn) corrisponda a un solo path. Viene eseguito anche per /admin/users e per ogni altro path sotto /admin, con ogni metodo. Per proteggere una sola route, passa il middleware ad app.get('/admin', fn, handler).
Domande frequenti
Che differenza c'è tra un middleware e un route handler?
Tecnicamente nessuna: sono entrambi funzioni (req, res, next). Per convenzione un route handler chiude la richiesta con una risposta, mentre un middleware di solito fa un lavoro condiviso e chiama next().
Un middleware può essere async?
Sì. In Express 5 un middleware async che lancia un errore o restituisce una promise rifiutata manda l'errore all'error handler in automatico. Fai await di quello che ti serve, poi chiama next().
Cosa fa next('route')?
Salta gli handler rimanenti della route corrente e passa alla route successiva che corrisponde. Funziona solo negli handler aggiunti con app.get(), app.post() e le altre funzioni dei metodi, non in app.use().
Come salto un middleware per una sola route?
Registra quella route prima del middleware, così risponde per prima, oppure controlla il path dentro il middleware (if (req.path === '/health') return next();). Applicare il middleware per router o per route invece che a tutta l'app spesso elimina il problema.