Exprese la siguiente función, ¿para qué sirve realmente?

124

He estado tratando de encontrar una buena descripción de lo que hace el next()método. En la documentación de Express dice que next('route')se puede usar para saltar a esa ruta y omitir todas las rutas intermedias, pero a veces nextse llama sin argumentos. ¿Alguien sabe de un buen tutorial, etc. que describa la nextfunción?

Andreas Selenwall
fuente

Respuestas:

160

next()sin argumentos dice "es broma, no quiero manejar esto". Regresa e intenta encontrar la siguiente ruta que coincida.

Esto es útil, por ejemplo, si desea tener algún tipo de administrador de página con slugs de URL, así como muchas otras cosas, pero aquí hay un ejemplo.

app.get('/:pageslug', function(req, res, next){
  var page = db.findPage(req.params.pageslug);
  if (page) {
    res.send(page.body);
  } else {
    next();
  }
});

app.get('/other_routes', function() {
  //...
});

Ese código inventado debería verificar una base de datos para una página con un cierto slug de identificación. Si encuentra uno, ¡renderízalo! Si no encuentra uno, ignore este controlador de ruta y busque otros.

Entonces, next()sin argumentos, permite fingir que no manejó la ruta para que otra cosa pueda recogerla.


O un contador de visitas con app.all('*'). Lo que le permite ejecutar un código de configuración compartido y luego pasar a otras rutas para hacer algo más específico.

app.all('*', function(req, res, next){
  myHitCounter.count += 1;
  next();
});

app.get('/other_routes', function() {
  //...
});
Alex Wayne
fuente
¡Gran respuesta! He visto algún otro uso de next también, por ejemplo next (err) y next ('route'). ¿Tiene ahora el propósito de estos, cuándo le gustaría propagar un error y cuándo le gustaría saltar a una ruta determinada?
Andreas Selenwall
8
@AndreasSelenwall next('route')es específico app.VERB()y se usa cuando una ruta tiene múltiples devoluciones de llamada para " omitir las devoluciones de llamada restantes de la ruta " .next(err) Se usa para saltar a cualquier " middleware de error " ( Ede la publicación).
Jonathan Lonowski el
55
Votado Solo por esta frase: "es broma, no quiero manejar esto" me hiciste entender lo que estaba buscando. Vi muchas preguntas similares y encontré la solución en una frase.
Pedro Barros
8
Llamar next()sin argumentos realmente no le dice al sistema "no quiero manejar esto", solo le dice al sistema que continúe procesando cualquier middlewares restante después de que se haga esto. No es una condición de error llamar next(), es parte del flujo normal. Si no llama, next()no se procesarán otras rutas.
d512
1
Desearía que se escribieran más respuestas en este sitio web para el profano ... 'next () sin argumentos dice "es broma, no quiero encargarme de esto"' - Perfecto para novatos ... (@ d512 tiene un mejor explicación)
daCoda
129

En la mayoría de los marcos, recibe una solicitud y desea devolver una respuesta. Debido a la naturaleza asíncrona de Node.js, tiene problemas con las devoluciones de llamadas anidadas si está haciendo cosas no triviales. Para evitar que esto suceda, Connect.js (antes de v4.0, Express.js era una capa encima de connect.js) tiene algo que se llama middleware, que es una función con 2, 3 o 4 parámetros.

function (<err>, req, res, next) {}

Su aplicación Express.js es una pila de estas funciones.

ingrese la descripción de la imagen aquí

El enrutador es especial, es un middleware que le permite ejecutar uno o más middleware para una determinada URL. Entonces es una pila dentro de una pila.

Entonces, ¿qué hace después? Simple, le dice a su aplicación que ejecute el próximo middleware. ¿Pero qué pasa cuando pasas algo a la siguiente? Express abortará la pila actual y ejecutará todo el middleware que tenga 4 parámetros.

function (err, req, res, next) {}

Este middleware se usa para procesar cualquier error. Me gusta hacer lo siguiente:

next({ type: 'database', error: 'datacenter blew up' });

Con este error, probablemente le diría al usuario que algo salió mal y registraré el error real.

function (err, req, res, next) {
   if (err.type === 'database') {
     res.send('Something went wrong user');
     console.log(err.error);
   }
};

Si imagina su aplicación Express.js como una pila, probablemente podrá solucionar muchas rarezas usted mismo. Por ejemplo, cuando agrega su middleware Cookie después de enrutador, tiene sentido que sus rutas no tengan cookies.

Pickels
fuente
3
¿Dónde almacenarías esta función de registro anónimo?
dennismonsewicz
"Express abortará la pila actual y ejecutará todo el middleware que tenga 4 parámetros". Me preguntaba cómo express es capaz de ejecutar el middleware de controlador de error exacto. ¡Gracias!
Abhishek Agarwal
75

En mi humilde opinión, la respuesta aceptada a esta pregunta no es realmente precisa. Como han dicho otros, en realidad se trata de controlar cuándo se ejecuta el siguiente controlador de la cadena. Pero quería proporcionar un poco más de código para hacerlo más concreto. Digamos que tiene esta sencilla aplicación express:

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

app.get('/user/:id', function (req, res, next) {
    console.log('before request handler');
    next();
});

app.get('/user/:id', function (req, res, next) {
    console.log('handling request');
    res.sendStatus(200);
    next();
});

app.get('/user/:id', function (req, res, next) {
    console.log('after request handler');
    next();
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!')
});

Si lo haces

curl http://localhost:3000/user/123

verá esto impreso en la consola:

before request handler
handling request
after request handler

Ahora, si comentas la llamada next()en el controlador central de esta manera:

app.get('/user/:id', function (req, res, next) {
    console.log('handling request');
    res.sendStatus(200);
    //next();
});

Verá esto en la consola:

before request handler
handling request

Observe que el último controlador (el que imprime after request handler ) no se ejecuta. Eso es porque ya no le estás diciendo a express que ejecute el siguiente controlador.

Por lo tanto, realmente no importa si su controlador "principal" (el que devuelve 200) fue exitoso o no, si desea que se ejecute el resto de los middlewares, debe llamar next().

¿Cuándo sería esto útil? Supongamos que desea registrar todas las solicitudes que llegaron a alguna base de datos, independientemente de si la solicitud se realizó correctamente o no.

app.get('/user/:id', function (req, res, next) {
    try {
       // ...
    }
    catch (ex) {
       // ...
    }
    finally {
       // go to the next handler regardless of what happened in this one
       next();
    }
});

app.get('/user/:id', function (req, res, next) {
    logToDatabase(req);
    next();
});

Si desea que se ejecute el segundo controlador, debe llamar next()al primer controlador.

Recuerde que el nodo es asíncrono, por lo que no puede saber cuándo finalizó la devolución de llamada del primer controlador. Tienes que decirlo llamando next().

d512
fuente
Sonfar la mejor respuesta para mí.
Norayr Ghukasyan
Bien explicacion!
Chang
7

next () sin parámetro invoca el siguiente controlador de ruta O el siguiente middleware en el marco.

kyasar
fuente
2
O el próximo middleware.
robertklep
1

Simplemente significa pasar el control al siguiente controlador.

Salud

Gammer
fuente
1

Observe la llamada anterior a next (). Llamar a esta función invoca la siguiente función de middleware en la aplicación. La función next () no es parte de Node.js o Express API, pero es el tercer argumento que se pasa a la función de middleware. La función next () podría llamarse cualquier cosa, pero por convención, siempre se llama "next". Para evitar confusiones, use siempre esta convención.

Hukmaram
fuente
0

La pregunta también se preguntó sobre el uso de next ('ruta') que parece estar cubierta la semana en las respuestas proporcionadas hasta ahora:

  1. USO DE next ():

En resumen: próxima función de middleware.

Extracto de esta documentación oficial de Express JS: página 'writing-middleware' :

"La función de middleware myLogger simplemente imprime un mensaje, luego pasa la solicitud a la siguiente función de middleware en la pila llamando a la función next ()".

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

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

app.listen(3000)

Esta página de la documentación de Express JS dice "Si la función de middleware actual no finaliza el ciclo de solicitud-respuesta, debe llamar a next () para pasar el control a la siguiente función de middleware. De lo contrario, la solicitud quedará suspendida".

  1. USO DE next ('ruta'):

En resumen: la siguiente ruta (frente a la siguiente función de middleware en el caso de next ())

Extracto de esta documentación de Express JS: página 'using-middleware' :

"Para omitir el resto de las funciones de middleware de una pila de middleware de enrutador, llame a next ('route') para pasar el control a la siguiente ruta . NOTA: next ('route') solo funcionará en las funciones de middleware que se cargaron mediante el app.METHOD () o router.METHOD () funciones.

Este ejemplo muestra una sub-pila de middleware que maneja las solicitudes GET a la ruta / user /: id ".

app.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) {
  res.render('special')
})
Ula
fuente
0

next () es el argumento de devolución de llamada a la función de middleware con req, y res es la solicitud http y los argumentos de respuesta a next en el siguiente código.

app.get ('/', (req, res, next) => {next ()});

Entonces next () llama a la función pasada en middleware. Si la función de middleware actual no finaliza el ciclo de solicitud-respuesta, debería llamar a next (), de lo contrario, la solicitud se quedará suspendida y se agotará el tiempo de espera.

next () fn debe llamarse dentro de cada función de middleware cuando se pasan varias funciones de middleware a app.use o app.METHOD, de lo contrario no se llamará a la siguiente función de middleware (en caso de que se pasen más de 1 funciones de middleware). Para omitir la llamada a las funciones de middleware restantes, llame a next ('route') dentro de la función de middleware y luego no se debe llamar a otras funciones de middleware. En el siguiente código, se llamará fn1 y también se llamará fn2, ya que next () se llama dentro de fn1. Sin embargo, no se llamará a fn3, ya que se llama a next ('route') dentro de fn2.

app.get('/fetch', function fn1(req, res, next)  {
console.log("First middleware function called"); 
    next();
}, 
function fn2(req, res, next) {
    console.log("Second middleware function called"); 
    next("route");
}, 
function fn3(req, res, next) {
    console.log("Third middleware function will not be called"); 
    next();
})
usuario3022150
fuente