2012-06-21 14 views
27

Mi piacerebbe scrivere una funzione middleware espressa che imposta un listener sull'evento 'end' della risposta, se ne esiste uno. Lo scopo è quello di eseguire la pulizia in base al codice di risposta http che il gestore finale ha deciso di inviare, ad es. registrazione del codice di risposta e rollback/commit di una transazione db. io voglio che questa pulizia sia trasparente per il chiamante finale.Come posso catturare un evento "risposta fine" in node.js + express?

Mi piacerebbe fare qualcosa di simile a quanto segue in espresso:

Il percorso middleware

function (req, res, next) { 
    res.on ('end', function() { 
     // log the response code and handle db 
     if (res.statusCode < 400) { db.commit() } else { db.rollback() } 
    }); 
    next(); 
} 

Il percorso:

app.post ("/something", function (req, res) { 
    db.doSomething (function() { 
     if (some problem) { 
      res.send (500); 
     } else { 
      res.send (200); 
     } 
    }); 
} 

Quando provo questo, la 'fine' il gestore di eventi non viene mai chiamato. Lo stesso per res.on('close'), di cui ho letto in un altro post. Questi eventi vengono licenziati?

L'unico altro modo che posso pensare di fare questo è il wrapping res.end o res.send con la mia versione in un middleware personalizzato. Questo non è l'ideale, perché res.end e res.send non accettano le richiamate, quindi non posso semplicemente racchiuderle, chiamare l'originale e poi fare le mie cose basandomi sul codice di risposta che è stato impostato quando mi richiamano (perché hanno vinto " t richiamami).

C'è un modo semplice per farlo?

+0

Perché non fare le cose di pulizia prima di 'res.end'? –

+0

Anche questo va bene, ma voglio farlo come middleware, cioè senza che il gestore finale debba preoccuparsi della pulizia. Quindi, se voglio registrare il codice di risposta risultante, o eseguire il rollback/commit della transazione db in base al codice di risposta, voglio che funzioni in modo trasparente al gestore finale. Quindi sto cercando di intercettare l'esecuzione ad un certo punto tra l'end handler che chiama res.send e la richiesta che viene eseguita. – Jake

+0

Ma ** tu ** stai definendo il codice di stato:/ –

risposta

1

Leggendo il documentation, ecco la firma del res.send:

res.send(body|status[, headers|status[, status]]) 

Il che significa che è possibile impostare il proprio stato, in questo modo: res.send('some string', 200); o anche solo res.send(404);.

Questo metodo è quello che si utilizza per inviare la risposta.

Una volta inviato al client, non è più possibile accedervi, quindi non vi è alcuna richiamata.

Questa è l'ultima cosa che fa il tuo server. Una volta che ha elaborato la richiesta, invia la risposta.

Tuttavia, è possibile accedervi prima del che si invia al client. Il che significa che è possibile:

console.log(res); 
res.send(datas); 

Se si desidera eseguire il rollback/commit, lo si fa quando richiamata del database viene chiamato, non quando la risposta è andato.

+0

Grazie. Dalla tua risposta, sembra che il modo in cui mi piacerebbe fare le cose è semplicemente impossibile senza sostituire res.send con la mia versione che fa la pulizia quindi chiama la reale ris. – Jake

+0

Sì, 'res.send()' è l'ultima cosa che l'app farà quando elaborerà la richiesta, quindi se vuoi fare una pulizia devi farlo prima :) :) –

+3

res.on ('header', func) FTW! – Hadesara

38

Stranamente, sembra che la risposta emette un evento "finire" quando la risposta è chiuso: http://sambro.is-super-awesome.com/2011/06/27/listening-for-end-of-response-with-nodeexpress-js/

Nonostante questo blog essere un po 'vecchio, questo evento esiste ancora (Line 836 in lib/http.js), così ho assumere non scomparirà presto, anche se né la documentazione di nessun nodo né quella espressa lo menzionano. All'inizio del 2014 è passato a line 504 on of lib/_http_outgoing.js e funziona ancora.

A proposito, l'evento "errore" su una risposta del server non è probabilmente qualcosa che di solito vorresti vedere.

+0

+1 Non sono riuscito a trovare la documentazione, ma il codice sorgente corrente (ad oggi) solleva ancora l'evento. Grazie! –

+0

Non riesco a farlo funzionare con finitura o fine o chiusura. eventuali suggerimenti? – Hadesara

+1

res.on ('header', func) FTW! – Hadesara

16

Giusto per ulteriori @ risposta di Amatsuyu, ecco come dovrebbe apparire:

res.on('finish', function() { 
    // do stuff here 
}); 
+0

Esiste un modo per ottenere l'accesso allo stato finale di res all'interno del callback? Ad esempio, il callback potrebbe esaminare res e estrarre i dati che sono stati inviati al client? –

+1

Sì @MatthewHerbst. Poiché questo listener di eventi viene gestito all'interno della chiamata dell'app.use, utilizzare lo stesso oggetto "res" da lì. – weexpectedTHIS

Problemi correlati