Node.js / Express.js: ¿cómo funciona app.router?

298

Antes de preguntar app.router, creo que debería explicar al menos lo que creo que sucede cuando trabajo con middleware. Para usar middleware, la función a usar es app.use(). Cuando se ejecuta el middleware, llamará al siguiente middleware mediante el uso next()o lo hará para que no se llame más middleware. Eso significa que el orden en el que coloco mis llamadas de middleware es importante, porque algunos middleware dependen de otro middleware, y algunos middleware cerca del final podrían ni siquiera ser llamados.

Hoy estaba trabajando en mi aplicación y tenía mi servidor ejecutándose en segundo plano. Quería hacer algunos cambios, actualizar mi página y ver los cambios de inmediato. Específicamente, estaba haciendo cambios en mi diseño. No pude hacerlo funcionar, así que busqué la respuesta de Stack Overflow para encontrar esta pregunta . Dice asegurarse de que express.static()esté debajo require('stylus'). Pero cuando estaba mirando el código de ese OP, vi que tenía su app.routerllamada al final de sus llamadas de middleware, y traté de entender por qué.

Cuando hice mi aplicación Express.js (versión 3.0.0rc4), usé el comando express app --sessions --css stylusy en mi archivo app.js el código vino configurado con mi app.routeranterior express.static()y las require('stylus')llamadas. Entonces parece que, si ya viene configurado de esa manera, entonces debería permanecer así.

Después de reorganizar mi código para poder ver los cambios de mi Stylus, se ve así:

app.configure(function(){
  //app.set() calls
  //app.use() calls
  //...
  app.use(app.router);
  app.use(require('stylus').middleware(__dirname + '/public'));
  app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});

app.get('/', routes.index);

app.get('/test', function(req, res){
  res.send('Test');
});

Así que decidí que el primer paso sería descubrir por qué es importante incluso tenerlo app.routeren mi código. Así que lo comenté, comencé mi aplicación y navegué a /. Se muestra mi página de índice muy bien. Hmm, tal vez funcionó porque estaba exportando la ruta desde mi archivo de rutas (routes.index). Entonces, a continuación, navegué /testy se mostró Prueba en la pantalla. Jaja, está bien, no tengo idea de lo que app.routerhace. Ya sea que esté incluido en mi código o no, mi enrutamiento está bien. Así que definitivamente me estoy perdiendo algo.

Ésta es mi pregunta:

¿Podría alguien explicarme qué app.routerhace, la importancia de esto y dónde debo colocarlo en mis llamadas de middleware? También sería bueno si recibiera una breve explicación sobre express.static(). Por lo que puedo decir, express.static()es un caché de mi información, y si la aplicación no puede encontrar la página solicitada, verificará el caché para ver si existe.

Aust
fuente
18
Gracias por hacer esta pregunta. He estado buscando en Google para encontrar esta respuesta (y la pregunta para solicitarla).
Hari Seldon el
8
Esa fue una pregunta muy bien escrita, estaba buscando en Google lo mismo.
Kirn

Respuestas:

329

Nota: Esto describe cómo funciona Express en las versiones 2 y 3. Consulte el final de esta publicación para obtener información sobre Express 4.


staticsimplemente sirve archivos ( estático recursos ) del disco. Le das una ruta (a veces llamada el punto de montaje), y sirve los archivos en esa carpeta.

Por ejemplo, express.static('/var/www')serviría los archivos en esa carpeta. Así que una petición al servidor de nodo para http://server/file.htmlserviría /var/www/file.html.

routeres un código que ejecuta tus rutas. Cuando lo hace app.get('/user', function(req, res) { ... });, es lo routerque realmente invoca la función de devolución de llamada para procesar la solicitud.

El orden al que pasa las cosas app.usedetermina el orden en que cada middleware tiene la oportunidad de procesar una solicitud. Por ejemplo, si tiene un archivo llamado test.htmlen su carpeta estática y una ruta:

app.get('/test.html', function(req, res) {
    res.send('Hello from route handler');
});

¿Cuál se envía a un cliente que lo solicita http://server/test.html? Cualquier middleware que se le dé useprimero.

Si haces esto:

app.use(express.static(__dirname + '/public'));
app.use(app.router);

Luego se sirve el archivo en el disco.

Si lo haces al revés,

app.use(app.router);
app.use(express.static(__dirname + '/public'));

Luego, el controlador de ruta recibe la solicitud y se envía al navegador "Hola desde el controlador de ruta".

Por lo general, desea colocar el enrutador arriba el middleware estático para que un archivo nombrado accidentalmente no pueda anular una de sus rutas.

Tenga en cuenta que si no lo hace de forma explícita useel router, se añade implícitamente por expreso en el punto que define una ruta (por eso sus rutas aún funcionaban a pesar de que en comentario app.use(app.router)).


Un comentarista ha planteado otro punto sobre el orden staticy routerque no había abordado: el impacto en el rendimiento general de su aplicación.

Otra razón para lo use routeranterior statices optimizar el rendimiento. Si lo coloca staticprimero, accederá al disco duro en cada solicitud para ver si existe o no un archivo. En una prueba rápida , descubrí que esta sobrecarga ascendía a ~ 1 ms en un servidor descargado. (Es probable que ese número sea mayor bajo carga, donde las solicitudes competirán por el acceso al disco).

Con routerla primera, una solicitud que coincide con una ruta nunca tiene que golpear el disco, ahorrando milisegundos preciosos.

Por supuesto, hay formas de mitigar staticlos gastos generales.

La mejor opción es colocar todos sus recursos estáticos en una carpeta específica. (IE /static) Luego puede montar staticen esa ruta para que solo se ejecute cuando la ruta comienza con /static:

app.use('/static', express.static(__dirname + '/static'));

En esta situación, pondrías esto arriba router. Esto evita el procesamiento de otro middleware / enrutador si hay un archivo presente, pero para ser honesto, dudo que ganes tanto.

También puede usar staticCache, que almacena en caché los recursos estáticos en la memoria para que no tenga que presionar el disco para los archivos solicitados comúnmente. ( Advertencia: staticCache aparentemente se eliminará en el futuro).

Sin embargo, no creo que staticCacheguarde en caché las respuestas negativas (cuando no existe un archivo), por lo que no ayuda si lo ha puesto staticCachearriba routersin montarlo en una ruta.

Al igual que con todas las preguntas sobre el rendimiento, mida y compare su aplicación del mundo real (bajo carga) para ver dónde están realmente los cuellos de botella.


Expreso 4

Express 4.0 elimina app.router . Todos los middleware ( app.use) y rutas (app.get et al) ahora se procesan exactamente en el orden en que se agregan.

En otras palabras:

Todos los métodos de enrutamiento se agregarán en el orden en que aparecen. Usted debe no hacerlo app.use(app.router). Esto elimina el problema más común con Express.

En otras palabras, mezclar app.use()y app[VERB]()funcionará exactamente en el orden en que se llaman.

app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);

Lea más sobre los cambios en Express 4.

josh3736
fuente
2
El routerva en un solo lugar. Si, la primera vez que se llama app.get(o post, u otros), aún no se ha used app.router, agrega expreso por usted.
josh3736
44
@MikeCauser: No, porque la sobrecarga del acceso al disco (para ver si existe o no un archivo) es mayor que la sobrecarga de la invocación de la función. En mi prueba , esa sobrecarga ascendió a 1 ms en un servidor descargado. Es muy probable que sea mayor bajo carga, donde las solicitudes competirán por el acceso al disco. Con staticafter router, la pregunta sobre el otro middleware se vuelve irrelevante ya que debe estar por encima del enrutador.
josh3736
2
Maravillosa explicación! Muchas gracias!
Kirn
3
app.routerse elimina en la rama maestra actual, que será express-4.0 . Cada ruta se convierte en un middleware separado.
yanychar
3
Una aclaración más, mientras trabajo con esto. En express 4, se pueden asignar múltiples rutas a un enrutador, y luego, para usar el enrutador, se le asigna una ruta raíz y se coloca en la pila de "middleware" a través de app.use (ruta, enrutador). Esto permite que las rutas relacionadas usen su propio enrutador y se les asigne una ruta base como una unidad. Si lo entendiera mejor, me ofrecería publicar otra respuesta. Nuevamente, obtengo
Joe Lapp
2

El enrutamiento significa determinar cómo una aplicación responde a una solicitud del cliente a un punto final particular, que es un URI (o ruta) y un método de solicitud HTTP específico (GET, POST, etc.). Cada ruta puede tener una o más funciones de controlador, que se ejecutan cuando la ruta coincide.

En Express 4.0 Router, tenemos más flexibilidad que nunca para definir nuestras rutas.

express.Router () se usa varias veces para definir grupos de rutas.

ruta utilizada como middleware para procesar solicitudes.

ruta utilizada como middleware para validar parámetros utilizando ".param ()".

app.route () se usa como acceso directo al enrutador para definir múltiples solicitudes en una ruta

cuando usamos app.route (), adjuntamos nuestra aplicación con ese enrutador.

var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS. 
app.get('/', function (req, res) {
  res.render('index');  
})
app.get('/test', function (req, res) {
  res.send('test')
})
Parth Raval
fuente
0

En la versión express 4 podemos definir fácilmente rutas de la siguiente manera:

server.js:

const express = require('express');
const app = express();
const route = require('./route');

app.use('/route', route);
// here we pass in the imported route object

app.listen(3000, () => console.log('Example app listening on port 3000!'));

route.js:

const express = require('express');
const router = express.Router();

router.get('/specialRoute', function (req, res, next) {
     // route is now http://localhost:3000/route/specialRoute
});

router.get('/', function (req, res, next) {
    // route is now http://localhost:3000/route
});

module.exports = router;

En server.jsimportamos el objeto enrutador del route.jsarchivo y lo aplicamos de la siguiente manera en server.js:

app.use('/route', route);

Ahora todas las rutas en el route.jstienen la siguiente URL base:

http: // localhost: 3000 / route

Por qué este enfoque:

La principal ventaja de adoptar este enfoque es que ahora nuestra aplicación es más modular . Todos los controladores de ruta para una ruta determinada ahora se pueden colocar en diferentes archivos, lo que hace que todo sea más fácil de mantener y encontrar.

Willem van der Veen
fuente