简体   繁体   中英

How does this Node.js middleware work without arguments?

I'm using a function that someone else wrote for express and passport , which defines the middleware(?) as follows:

function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()){ 
        return next(); 
    }
    else{
        req.flash('error', 'You need to be logged in to access this page');
        res.redirect('/login');
    }
}

This function is used in the router as follows:

app.get('/page', isLoggedIn, function(req, res){
    // ...
});

What I don't understand is, shouldn't the function be called with parameters req and res ? Maybe the callback next is not necessary since it's the next argument of app.get , but how does the function access req and res ? I would expect it to be called as follows:

app.get('/page', isLoggedIn(req, res), function(req, res){
    // ...
});

How does it work without specifying the arguments?

Thanks,

Any functions that you pass to app.get() or app.use() are automatically called with req, res, next passed to them. That is how app.get() and app.use() are implemented.

To help you understand, this example:

app.get('/page', function(req, res){
    console.log(req.params.foo);
});

is functionally the same as this:

app.get('/page', myHandler);

function myHandler(req, res) {
    console.log(req.params.foo);
});

You do not want to do something like this:

app.get('/page', isLoggedIn(req, res), function(req, res){
    // ...
});

because here you're attempting to execute isLoggedIn(req, res) (when req and res are not yet defined) and then pass it's returned value to app.get() . That is not what you want at all. You need to pass a function reference to app.get() and it will supply the parameters when it calls the function. Any time you put () after a function in Javascript, that means you want to execute it NOW. But, if you just pass the function's name, then that is a function reference which can be stored and called later as desired.

This code example is analogous to this:

var result = isLoggedIn(req, res);

app.get('/page', result, function(req, res){
    // ...
});

Besides the fact that this would cause an error because req and res are not defined at program start time when this would execute, hopefully you can see that you don't want to execute isLoggedIn() now. Instead, you just want to pass a function reference so Express can call it later.

In this code

app.get('/page', isLoggedIn, function(req, res){
    // ...
});

The app.get method is being called with three arguments:

  1. the route to the page: /page
  2. the middleware function
  3. the request handler function

Basically, this code is telling the express framework that when a GET request is received for the /page path, then it should call two functions: first, the middleware function and second the handler function.

The important thing to note here is that it is the framework doing the work. The framework is going to call the middleware function, then it's going to call the handler function.

What I don't understand is, shouldn't the function be called with parameters req and res?

It will be called with these arguments, somewhere inside the get function. Suppose this is the simplified get , implemented as

// a super simple get that will expect a function
// and call the function with two arguments
function get( f ) {
    var res = 1, req = 1;
    f( res, req );
}

There are multiple ways of passing a function to get . For example, you pass an anonymous function

get( function( res, req ) {
   return res + req;
}

You can also pass a named function defined elsewhere

function isLoggedIn( res, req ) {
   return res + req;
}

get( isLoggedIn );

This however, is not what you'd expect:

get( isLoggedIn( res, req ) );

The problem here is that

isLoggedIn( res, req )

is no longer a function declaration . It is an invocation and the result of this invocation depends on what res and req are. With some luck, the invocation can even yield a number value, which means that get is no longer invoked with function as an argument but with the result of function invocation.

In short, to pass a named function to another function, you don't specify its arguments. The supposed syntax that would allow this doesn't even make sense because it would be indistinguishable from a syntax of actual function invocation (ie the value of the call).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM