Node Express 4 middleware after routes
Asked Answered
A

5

61

Following the upgrade to Express 4, and the removal of app.router, I'm struggling to get middleware to execute after routes execute.

e.g. the following code correctly responds with "hello", but never calls the configured middleware

var express = require( "express" )();

express.get( "/", function( req, res ) {

    res.send( "hello" );

} );
express.use( function( req, res, next ) {

    console.log( "world" );
    next();

} );

express.listen( 8888 );

CLARIFICATION:

the following code shows "before" on the console, but not "after":

var express = require( "express" )();

express.use( function( req, res, next ) {

    console.log( "before" );
    next();

} );
express.get( "/", function( req, res ) {

    res.send( "hello" );

} );
express.use( function( req, res, next ) {

    console.log( "after" );
    next();

} );

express.listen( 8888 );
Atomize answered 17/6, 2014 at 8:9 Comment(7)
Works for me. What doesn't work for you.Conveyancing
I never see the console.log outputAtomize
Shows for me at the node.js commandline. Do you have additional code ?Conveyancing
No that's it. What version of express are you running? (I'm on 4.4)Atomize
Mine is 4.4.3. Try it.Conveyancing
Same as mine. Node version 0.11.10 on OS/XAtomize
Let us continue this discussion in chat.Atomize
R
64

In regards to Express 4, the "after" function from your second example never gets called because the middle function never calls next().

If you want the "after" function to get called, then you need to add and call the next callback from your middle function like this:

var express = require( "express" )();

express.use( function( req, res, next ) {
  
  console.log( "before" );
  next();
  
} );
express.get( "/", function( req, res, next ) {

  res.send( "hello" );
  next();      // <=== call next for following middleware 

} );
express.use( function( req, res, next ) {

  console.log( "after" );
  next();

} );

express.listen( 8888 );

res.send() writes the headers and response back to the client.

Beware, that once res.send() has been called, you won't want to update your response headers or contents. But you can do other tasks like database updates or logging.

Note that express looks at the the number of arguments in the middleware function and does different logic. Take express error handlers for example, which have 4 parameters defined.

express error handler signature:

app.use(function(err, req, res, next) {});

Calling next on the very last item in your middleware chain is optional, but probably a good idea in case you ever change things around.

Roach answered 4/4, 2015 at 2:29 Comment(1)
Now that's true. Most of the examples for express show routes being specified with an arity of 2 in the handling function. But doing so precludes ever adding middleware which should execute after the route has been handled. That seems like a strange convention for them to establish.Atomize
C
130

The correct answer is using the res.on("finish", cb) callback.

i.e.:

express.use(function(req, res, next) {
    console.log("before");

    res.on("finish", function() {
        console.log("after");
    });

    next();
});
Cabot answered 21/8, 2017 at 22:42 Comment(5)
this guy says "res.once", not "res.on" lunchbadger.com/…Theatrics
@datdinhquoc It doesn't matter really since the res will not be available after the Express done with the response object, since every request causes a new req & res pair to be created (by Express). You are right and normally what a responsible developer should do, but in this particular case they are the same.Kernel
@Catfish this is using node's http module response features node docs. As you'll see in the express docs, express's "res object is an enhanced version of Node’s own response object and supports all built-in fields and methods."Shetler
This method is good for when people have already made an API without using next in all their routes.Florid
This was super helpful. I was able to implement auditing that I start an audit and submit to sql before the route, then after the route I update the audit in sql with the res.statusCode. Thanks to test and Nicholas for res.on("finish", async () => {})Sacci
R
64

In regards to Express 4, the "after" function from your second example never gets called because the middle function never calls next().

If you want the "after" function to get called, then you need to add and call the next callback from your middle function like this:

var express = require( "express" )();

express.use( function( req, res, next ) {
  
  console.log( "before" );
  next();
  
} );
express.get( "/", function( req, res, next ) {

  res.send( "hello" );
  next();      // <=== call next for following middleware 

} );
express.use( function( req, res, next ) {

  console.log( "after" );
  next();

} );

express.listen( 8888 );

res.send() writes the headers and response back to the client.

Beware, that once res.send() has been called, you won't want to update your response headers or contents. But you can do other tasks like database updates or logging.

Note that express looks at the the number of arguments in the middleware function and does different logic. Take express error handlers for example, which have 4 parameters defined.

express error handler signature:

app.use(function(err, req, res, next) {});

Calling next on the very last item in your middleware chain is optional, but probably a good idea in case you ever change things around.

Roach answered 4/4, 2015 at 2:29 Comment(1)
Now that's true. Most of the examples for express show routes being specified with an arity of 2 in the handling function. But doing so precludes ever adding middleware which should execute after the route has been handled. That seems like a strange convention for them to establish.Atomize
H
2

Have you checked putting your console.log after the next() call?

express.use( function( req, res, next ) {
  next();
  console.log( "world" );
});
express.get( "/", function( req, res ) {
  res.send( "hello" );
});
Helpmeet answered 12/3, 2015 at 22:41 Comment(2)
It looks like a robust variant.Riyadh
This will not work right if the request does anything asynchronousCrocoite
R
2
const beforeMiddleware = function(req, res, next) {
  console.log('Before middleware triggered');
  next();
}

const responseHandler = function(req, res, next) {
    console.log('Response handler');
    res.status(200).send("Hello world");
    next();
}

const afterMiddleware = function(req, res, next) {
    console.log('After middleware triggered');
    next();
}

app.get('/', beforeMiddleware, handler, afterMiddleware);
Rowlock answered 17/1, 2022 at 9:53 Comment(0)
R
0

you can use the Middle ware function in different js file and you can use require function. so that it will be called before and after the http request.

    index.js:     
        const logger = require("./logger");    
           const express = require("express");    
           var app = express();    
           app.listen("3000",()=>console.log("listening on 3000..."))    
        app.use(logger("AppServer"));    
        //get expression    
        app.get("/", function(req,res){    
           console.log("res not received");    
            res.send("Hello World");    
           console.log("res received");    
        })   

    logger.js   

    module.exports = (applicationName) =>{
        return function log(req,res,next){
       console.log(applicationName+" started "+os.hostname);
        res.on("finish",()=>{
            console.log(applicationName+" completed "+os.hostname);
        })
        next();
        }};

output:   
AppServer started hostname-PC   
res not received   
res received   
AppServer completed hostname-PC 

Note: in the logger.js instead of using res.on("finish",callback), you can use req.on("end",callback)

Rubescent answered 10/8, 2019 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.