¿Para qué se utiliza el parámetro "siguiente" en Express?

Resuelto Menztrual asked hace 12 años • 6 respuestas

Supongamos que tiene un bloque de código simple como este:

app.get('/', function(req, res){
    res.send('Hello World');
});

Esta función tiene dos parámetros, reqy res, que representan los objetos de solicitud y respuesta respectivamente.

Por otro lado, existen otras funciones con un tercer parámetro llamado next. Por ejemplo, echemos un vistazo al siguiente código:

app.get('/users/:id?', function(req, res, next){ // Why do we need next?
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next(); // What is this doing?
    }
});

No puedo entender cuál next()es el punto o por qué se usa. En ese ejemplo, si la identificación no existe, ¿qué está nexthaciendo realmente?

Menztrual avatar May 22 '12 11:05 Menztrual
Aceptado

Pasa el control a la siguiente ruta coincidente . En el ejemplo que da, por ejemplo, puede buscar el usuario en la base de datos si idse proporcionó un y asignarlo a req.user.

A continuación, podría tener una ruta como:

app.get('/users', function(req, res) {
  // check for and maybe do something with req.user
});

Dado que /users/123 coincidirá primero con la ruta en su ejemplo, primero verificará y encontrará user 123; Entonces /userspuedo hacer algo con el resultado de eso.

Sin embargo, en mi opinión, el middleware de ruta es una herramienta más flexible y poderosa, ya que no depende de un esquema de URI particular ni de un orden de ruta. Me inclinaría por modelar el ejemplo que se muestra así, asumiendo un Usersmodelo con async findOne():

function loadUser(req, res, next) {
  if (req.params.userId) {
    Users.findOne({ id: req.params.userId }, function(err, user) {
      if (err) {
        next(new Error("Couldn't find user: " + err));
        return;
      }

      req.user = user;
      next();
    });
  } else {
    next();
  }
}

// ...

app.get('/user/:userId', loadUser, function(req, res) {
  // do something with req.user
});

app.get('/users/:userId?', loadUser, function(req, res) {
  // if req.user was set, it's because userId was specified (and we found the user).
});

// Pretend there's a "loadItem()" which operates similarly, but with itemId.
app.get('/item/:itemId/addTo/:userId', loadItem, loadUser, function(req, res) {
  req.user.items.append(req.item.name);
});

Ser capaz de controlar un flujo como este es bastante útil. Es posible que desees que ciertas páginas solo estén disponibles para usuarios con una marca de administrador:

/**
 * Only allows the page to be accessed if the user is an admin.
 * Requires use of `loadUser` middleware.
 */
function requireAdmin(req, res, next) {
  if (!req.user || !req.user.admin) {
    next(new Error("Permission denied."));
    return;
  }

  next();
}

app.get('/top/secret', loadUser, requireAdmin, function(req, res) {
  res.send('blahblahblah');
});

¡Espero que esto te haya servido de inspiración!

Ashe avatar May 22 '2012 04:05 Ashe

También tuve problemas para entender next() , pero esto ayudó

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

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write("Hello");
    next(); //remove this and see what happens 
});

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write(" World !!!");
    httpResponse.end();
});

app.listen(8080);
rajesk avatar Jun 25 '2016 15:06 rajesk

Antes de comprenderlo next, debe tener una pequeña idea del ciclo Solicitud-Respuesta en el nodo, aunque no mucho en detalle. Comienza cuando usted realiza una solicitud HTTP para un recurso en particular y finaliza cuando envía una respuesta al usuario, es decir, cuando encuentra algo como res.send('Hello World');

echemos un vistazo a un ejemplo muy simple.

app.get('/hello', function (req, res, next) {
  res.send('USER')
})

Aquí no necesitamos next(), porque resp.send finalizará el ciclo y devolverá el control al middleware de ruta.

Ahora echemos un vistazo a otro ejemplo.

app.get('/hello', function (req, res, next) {
  res.send("Hello World !!!!");
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});

Aquí tenemos 2 funciones de middleware para la misma ruta. Pero siempre obtendrás la respuesta del primero. Porque eso se monta primero en la pila de middleware y res.send finalizará el ciclo.

Pero ¿y si no siempre queremos el mensaje “¡¡¡Hola mundo!!!!” respuesta de vuelta. Para algunas condiciones es posible que deseemos el mensaje "¡¡¡Hola Planeta!!!!" respuesta. Modifiquemos el código anterior y veamos qué sucede.

app.get('/hello', function (req, res, next) {
  if(some condition){
    next();
    return;
  }
  res.send("Hello World !!!!");  
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});

¿Qué nexthace aquí? Y sí, es posible que tengas nervios. Se omitirá la primera función de middleware si la condición es verdadera e invocará la siguiente función de middleware y obtendrá la "Hello Planet !!!!"respuesta.

Entonces, luego pase el control a la siguiente función en la pila de middleware.

¿Qué pasa si la primera función de middleware no envía ninguna respuesta pero ejecuta una parte de la lógica y luego obtiene la respuesta de la segunda función de middleware?

Algo como a continuación: -

app.get('/hello', function (req, res, next) {
  // Your piece of logic
  next();
});

app.get('/hello', function (req, res, next) {
  res.send("Hello !!!!");
});

En este caso, es necesario invocar ambas funciones del middleware. Entonces, la única forma de llegar a la segunda función de middleware es llamando a next();

¿Qué pasa si no haces una llamada al siguiente? No espere que la segunda función de middleware se invoque automáticamente. Después de invocar la primera función, su solicitud quedará suspendida. La segunda función nunca será invocada y no recibirás la respuesta.

Mav55 avatar Mar 20 '2018 15:03 Mav55

Siguiente se utiliza para pasar el control a la siguiente función de middleware. En caso contrario, la solicitud quedará suspendida o abierta.

Ronique Ricketts avatar Apr 14 '2017 19:04 Ronique Ricketts

Un poco de interior aquí. El objetivo principal de express app handlela función es enviar una respuesta al cliente y finalizar el archivo request-response cycle. Y la terminación de este ciclo se puede realizar mediante uno de response methods(por ejemplo, res.end(), res.json(), etc.). Es decir, si un middleware route handlerrealiza algunas acciones pero luego no llama a uno de ellos response methodsni pasa el control al siguiente controlador o middleware, request-response cycleno se terminará. Pero lo que nexthace depende de dónde y cómo se llama.

Para gestionar diferentes tareas (manejadores de ruta, middlewares) expressse crea stacks. Parecen uno queuede los tasks. Cada uno routercrea routeel suyo stackpropio tasks;

El usemétodo de los express apppush task( middlewarefunción) al stackdel router. El app.get,, app.postetc. crea un separado route(con su propio stack, y empuja hacia él el real handlersdel route) en el router, luego empuja hacia los routerenvueltos en una función esos routecontroladores. Es decir, cuando routese crea router stackalgo así como route task(función contenedora) con subtaskspush.

// pushes task to the router stack
app.use((req, res, next) => {
    console.log('log request');
    next();
});

// creates route, route stack, 
// pushes tasks to the route stack,
// wraps tasks in a function (another task)
// pushes wrapper function to the
// router stack
app.get('/', (req, res, next) => {
    res.send('Hello World');
});

Como a routetiene su propia stackllamada nextsin los argumentos, solo nos lleva al siguiente controlador de route:

app.get('/', 
    (req, res, next) => {
        console.log('first handler');
        // passes the control to the second handler
        next();
    },
    (req, res, next) => {
        console.log('second handler');
        res.send('Hello World');
    }
);

Llamar nextdentro de a middleware( expressse recomienda aplicar useel método para montar a middleware) nos lleva al siguiente routeo middlewaredel router, porque middleware(cuando se montó) se empujó al router stack.

nextAcepta diferentes argumentos. Cualquier argumento que no sea 'route'o 'router'será tratado como un error y se pasará al error middlewareque debe montarse después de todas las rutas y tener cuatro argumentos:

// error handling middleware
app.use((error, req, res, next) => {
    res.status(error.status || 500);
    res.send(error.message || 'Server internal error');
});

La cadena 'route'como argumento para nextomitirá todo lo restante route handlersy nos dará el siguiente routede router:

app.get('/', 
    (req, res, next) => {
        console.log('first handler');
        // passes control to the next route
        next('route');
    },
    (req, res, next) => {
        // this handler will be skipped
        next();
    }
);

app.get('/',
    (req, res, next) => {
        // this route will be called at the end
        res.send('Hello World');
    }
);

La cadena 'router'como argumento nextnos saca de la corriente router:

// router 'one'
app.get('/', 
    (req, res, next) => {
        console.log('first handler');
        // passes control to the next router
        next('router');
    },
    (req, res, next) => {
        // this handler will be skipped
        next();
    }
);

// router 'two'
app.get('/',
    (req, res, next) => {
        // this route will be called at the end
        res.send('Hello World');
    }
);
Vadi avatar Nov 03 '2022 12:11 Vadi