2012-07-04 10 views
11

Vorrei realizzare qualcosa di simile:Come eseguire un middleware NodeJS/connect dopo che è stato richiamato responde.end()?

var c = require('connect'); 
var app = c(); 

app.use("/api", function(req, res, next){ 
    console.log("request filter 1"); 
    next(); 
}); 

app.use("/api", function(req, res, next){ 
    console.log("request filter 2"); 
    next(); 
}); 

app.use("/api", function(req, res, next){ 
    console.log("request handler"); 
    res.end("hello"); 
    next(); 
}); 

app.use("/api", function(req, res, next){ 
    console.log("response post processor"); 
    next(); 
}); 
app.listen(3000); 

Quando mi rannicchio per l'indirizzo, ricevo un eccezione alla console lamentarsi intestazioni non possono essere disturbati dopo essere stato inviato, che è abbastanza giusto. Solo che non tocco l'oggetto risposta.

/usr/bin/node app2.js 
request filter 1 
request filter 2 
request handler 
Error: Can't set headers after they are sent. 
    at ServerResponse.OutgoingMessage.setHeader (http.js:644:11) 
    at ServerResponse.res.setHeader (/home/zpace/node_modules/connect/lib/patch.js:59:22) 
    at next (/home/zpace/node_modules/connect/lib/proto.js:153:13) 
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:25:5) 
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15) 
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:19:5) 
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15) 
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:14:5) 
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15) 
    at Function.app.handle (/home/zpace/node_modules/connect/lib/proto.js:198:3) 

test del livello di NodeJS/Connetti sono entrato in una parte che implica in qualche modo che se le intestazioni siano già inviati quindi l'esecuzione di un gestore di rotta deve inizializzare intestazioni di risposta.

La domanda è se il comportamento di cui sopra è intenzionale (vale a dire che l'esecuzione di qualsiasi codice dopo un gestore di percorso ha finito di inviare una risposta è qualcosa di assolutamente inimmaginabile o questo è semplicemente un bug in Connect?

+0

Stai facendo 'res.end (" ciao ")' nel tuo codice –

+0

sì. l'elaborazione della risposta viene eseguita, la risposta è pronta per essere trasmessa. e ora mi piacerebbe ad esempio inserire un registro o ripulire qualcosa. –

+0

Hai trovato un modo per farlo visto che hai fatto questa domanda? Sembra che non ci siano risposte su questo thread e sto cercando di capire perché il team di Connect ha implementato le cose come hanno fatto. – conradkdotcom

risposta

24

Non sono sicuro se hai trovato la soluzione.

Se si desidera progettare un post-processore per il ciclo di richiesta, è possibile utilizzare un middleware che ascolta l'evento "fine" sull'oggetto risposta. Come questo:

app.use(function(req, res, next){ 
    res.on('finish', function(){ 
    console.log("Finished " + res.headersSent); // for example 
    console.log("Finished " + res.statusCode); // for example 
    // Do whatever you want 
    }); 
    next(); 
}); 

verrà eseguita la funzione collegata alla manifestazione "finire" dopo la risposta viene scritto (che significa che il NodeJS ha consegnato fuori l'intestazione della risposta e il corpo per il sistema operativo per la trasmissione di rete).

Immagino che questo sia quello che vuoi.

+0

questo è ... grazie! –

+2

L'evento 'finish' non viene attivato nel caso in cui l'oggetto risposta abbia già attivato l'evento' close' - si verifica quando il socket viene chiuso prima di poter inviare una risposta. Se si vuole cogliere il momento in cui il ciclo di richiesta/risposta estremità (anche quando un middleware di gestione degli errori invia la risposta) forse è meglio per ignorare la funzione di 'FINE' della risposta: ' var _end = res .fine; res.end = function() { console.log ('la fine della risposta'); _end.apply (questo, argomenti); } ' – godness

+0

@godness buona idea. Grazie. – r3wt

2

penso questo è un problema di pianificazione male. si dovrebbe risolvere questo in un modo migliore. Non so il motivo per cui si dispone di un gestore di richiesta e di un processore richiesta POST separato, ma lascia scoprire cosa possiamo fare.

Quindi sì, dopo la risposta è finito non riesci a leggere di nuovo le intestazioni

Quindi non finisci la risposta fino a quando viene invocato il post processor.

var isEnd; 

app.use("/*", function(req, res, next){ 
    isEnd = false; 
}) 

app.use("/api", function(req, res, next){ 
    console.log("request handler"); 
    res.write("hello"); 
    isEnd = true; 
    next(); 
}); 

app.use("/api", function(req, res, next){ 
    console.log("response post processor"); 
    if(isEnd) { 
     res.end(); 
    } 
    else next(); 
}); 

Questo è un tipo di soluzione, ma questo potrebbe non essere il migliore per il tuo problema.

A mio parere è molto brutto che chiami next() dopo che la risposta è stata completata. Se hai bisogno di un post processore, perché lo fai in un filtro delle richieste (o cos'è questo). Chiamare una funzione, ma non next()

Forse questo:

app.use("/api", function(req, res, next){ 
    console.log("request handler"); 
    res.end("hello"); 
    setTimeout(function(){(postProcessor(req)},0); 
}); 

function postProcessor(req) { 
//doing post process stuff. 
//response not needed because already ended. 
} 

O questo:

app.use("/api", function(req, res, next){ 
    console.log("request handler"); 
    res.writed("hello"); 
    setTimeout(function(){(postProcessor(req)},0); 
    // u cant res.end here because setTimeout. 
    //If you dont use setTimeout you can use res.end here, but not bot function. 
}); 

function postProcessor(req, res) { 
//doing post process stuff. 
res.end(); 
} 

Il next() non è per questo utilizzo, ciò che si utilizza.

Spero che la mia risposta ti aiuti, ma so che non copre tutto, ma la tua risposta non è troppo concreta.

+0

Si consideri che il livello nodejs/connect viene popolato con logica mista da varie origini: A) codice che rappresenta la logica aziendale e B) codice che rappresenta l'infrastruttura. Quindi se due diversi ppl creano le parti di business e di infrastruttura non ci può essere sviluppo di cooperazione/fortemente accoppiata qui. Il responsabile della logica aziendale deve gestire le cose come se stesse lavorando da solo (inconsapevole dell'infrastruttura), il codice dell'infrastruttura ha bisogno dello stesso: essere agnostico per quanto riguarda il codice del livello aziendale. –

+0

E ancora: nell'ultima funzione (il "postprocessore") non sto toccando le intestazioni, corpi tutto ciò che è stato congelato. –

1

Che bella domanda provare con il caffè del mattino!

Così guardando attraverso proto.js, se si dispone di uno sguardo verso il basso per la linea 102 che è app.handle che è il codice del gestore per lo stack middleware, si vedrà come prossima() opera.

Dove viene chiamata la funzione next(), è possibile verificare se res.headerSent è true e in tal caso genera un errore.

Se la linea di modifica 14 a:

app.use("/api", function(req, res, next){ 
    console.log("request handler"); 
    res.end("hello"); 
    console.log(res); 
    next(); 
}); 

Si vedrà che in realtà imposta "headersSent" true. Quindi, dopo aver terminato la richiesta, è possibile vedere dal codice next() che genera l'errore a causa delle condizioni discusse.

+0

sì, ma l'invio della richiesta non significa necessariamente che abbiamo terminato il ciclo di richiesta. IMHO è solo un possibile approccio. –

Problemi correlati