¿Qué significa middleware y app.use realmente en Expressjs?

228

Casi todas las aplicaciones Express que veo tienen una app.usedeclaración para el middleware, pero no he encontrado una explicación clara y concisa de qué es realmente el middleware y qué app.useestá haciendo la declaración. Incluso los documentos expresos en sí mismos son un poco vagos en esto. ¿Me puede explicar estos conceptos por favor?

iZ.
fuente
3
pregunta similar para referencia (aunque esta fue creada anteriormente): stackoverflow.com/questions/11321635/…
ericsoco
43
^ ¡Ja! Estas dos preguntas se refieren entre sí en los comentarios.
Julian H. Lam
17
Entonces es una referencia circular.
Steve K
66
Express.js Middleware Demystified Una gran publicación de blog sobre el tema. Esto fue copiado aquí antes, lo cual es plagio, por supuesto, pero la publicación original sigue siendo realmente útil, así que dejo un enlace aquí.
totymedli
1
Escribí un artículo sobre el middleware express.js. Aquí está el enlace: nodexplained.com/blog-detail/2017/12/31/…
shrawan_lakhe

Respuestas:

111

middleware

Estoy a medio camino de separar el concepto de middleware en un nuevo proyecto.

Middleware le permite definir una pila de acciones por las que debe pasar. Los servidores Express son una pila de middlewares.

// express
var app = express();
// middleware
var stack = middleware();

Luego puede agregar capas a la pila de middleware llamando .use

// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
  next();
});

Una capa en la pila de middleware es una función, que toma n parámetros (2 para express, req& res) y una nextfunción.

Middleware espera que la capa haga algunos cálculos, aumente los parámetros y luego llame next.

Una pila no hace nada a menos que la manejes. Express manejará la pila cada vez que una solicitud HTTP entrante sea atrapada en el servidor. Con middleware manejas la pila manualmente.

// express, you need to do nothing
// middleware
stack.handle(someData);

Un ejemplo más completo:

var middleware = require("../src/middleware.js");

var stack = middleware(function(data, next) {
    data.foo = data.data*2;
    next();
}, function(data, next) {
    setTimeout(function() {
        data.async = true;
        next();
    }, 100)
}, function(data) {
    console.log(data);
});

stack.handle({
    "data": 42
})

En términos expresos, simplemente define una pila de operaciones que desea que express maneje para cada solicitud HTTP entrante.

En términos de express (en lugar de conectar), tiene middleware global y middleware específico de ruta. Esto significa que puede adjuntar una pila de middleware a cada solicitud HTTP entrante o solo adjuntarla a solicitudes HTTP que interactúen con una ruta determinada.

Ejemplos avanzados de express y middleware:

// middleware 

var stack = middleware(function(req, res, next) {
    users.getAll(function(err, users) {
        if (err) next(err);
        req.users = users;
        next();  
    });
}, function(req, res, next) {
    posts.getAll(function(err, posts) {
        if (err) next(err);
        req.posts = posts;
        next();
    })
}, function(req, res, next) {
    req.posts.forEach(function(post) {
        post.user = req.users[post.userId];
    });

    res.render("blog/posts", {
        "posts": req.posts
    });
});

var app = express.createServer();

app.get("/posts", function(req, res) {
   stack.handle(req, res); 
});

// express

var app = express.createServer();

app.get("/posts", [
    function(req, res, next) {
        users.getAll(function(err, users) {
            if (err) next(err);
            req.users = users;
            next();  
        });
    }, function(req, res, next) {
        posts.getAll(function(err, posts) {
            if (err) next(err);
            req.posts = posts;
            next();
        })
    }, function(req, res, next) {
        req.posts.forEach(function(post) {
            post.user = req.users[post.userId];
        });

        res.render("blog/posts", {
            "posts": req.posts
        });
    }
], function(req, res) {
   stack.handle(req, res); 
});
Raynos
fuente
44
Hmm ... ¿es el middleware en este caso tu propia biblioteca o parte de express?
iZ.
55
Frio. Todavía estoy un poco confundido por la app.use()sintaxis. ¿Cuál es el valor de retorno real del middleware y qué hace usecon él?
iZ.
99
El uso de @iZ lo agrega a una pila. Luego, cada solicitud pasa por la pila.
Raynos
77
@Raynos, el enlace a su proyecto, "middleware", está roto.
Lee
1
@Raynos pero veo que el middleware todavía se usa en Express? ¿Qué quieres decir con que está nuclear?
Timo Huovinen
60

Después de simplificar las cosas, un servidor web puede verse como una función que acepta una solicitud y genera una respuesta. Entonces, si ve un servidor web como una función, puede organizarlo en varias partes y separarlas en funciones más pequeñas para que la composición de ellas sea la función original.

Los middlewares son las funciones más pequeñas que puede componer con otros y el beneficio obvio es que puede reutilizarlas.

Barum Rho
fuente
33

Agrego una respuesta tardía para agregar algo que no se menciona en las respuestas anteriores.

Por ahora debería estar claro que el middleware es / son las funciones que se ejecutan entre la solicitud del cliente y la respuesta del servidor . La funcionalidad de middleware más común necesaria es la gestión de errores, la interacción de la base de datos, la obtención de información de archivos estáticos u otros recursos. Para moverse en la pila de middleware, se debe llamar a la siguiente devolución de llamada, puede verla al final de la función de middleware para pasar al siguiente paso del flujo.

Puede usar el app.useenfoque y tener un flujo como este :

var express = require('express'),
    app = express.createServer(),                                                                                                                                                 
    port = 1337;

function middleHandler(req, res, next) {
    console.log("execute middle ware");
    next();
}

app.use(function (req, res, next) {
    console.log("first middle ware");                                                                                                             
    next();
});

app.use(function (req, res, next) {
    console.log("second middle ware");                                                                                                             
    next();
});

app.get('/', middleHandler, function (req, res) {
    console.log("end middleware function");
    res.send("page render finished");
});

app.listen(port);
console.log('start server');

pero también puede usar otro enfoque y pasar cada middleware como argumentos de función. Aquí hay un ejemplo del sitio web de MooTools Nodejs donde midleware obtiene el flujo de Twitter, Github y Blog antes de que responsese envíe nuevamente al cliente. Observe cómo se pasan las funciones como argumentos en app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){. El uso app.getsolo se llamará para solicitudes GET, app.usese llamará para todas las solicitudes.

// github, twitter & blog feeds
var githubEvents = require('./middleware/githubEvents')({
    org: 'mootools'
});
var twitter = require('./middleware/twitter')();
var blogData = require('./blog/data');
function getLatestBlog(req, res, next){
    blogData.get(function(err, blog) {
        if (err) next(err);
        res.locals.lastBlogPost = blog.posts[0];
        next();
    });
}

// home
app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
    res.render('index', {
        title: 'MooTools',
        site: 'mootools',
        lastBlogPost: res.locals.lastBlogPost,
        tweetFeed: res.locals.twitter
    });
});
Sergio
fuente
2
Estaba buscando una respuesta para saber si Express.js admite el montaje de middleware basado en la ruta (NO en el enrutador). Parece que lo has demostrado en tu respuesta.
Selçuk
¿Puede explicar su ejemplo anterior ?, ¿cómo puede pasar tantas funciones a app.get (...) y en qué orden se llaman?
Tanner Summers el
2
Hola @TannerSummers, el .get()método toma 3 tipos de argumentos: el primero, el último y el medio. Internamente detecta si hay más argumentos que 2 y los usa (los del medio) como funciones de middleware, llamándolos de izquierda a derecha.
Sergio
22

La guía expressjs tiene una respuesta bastante clara a su pregunta, le recomiendo que lea eso, estoy publicando un breve fragmento de la guía, la guía es bastante buena.

Escribir middleware para usar en aplicaciones Express

Visión general

Las funciones de middleware son funciones que tienen acceso al objeto de solicitud ( req ), el objeto de respuesta ( res ) y la siguiente función en el ciclo de solicitud-respuesta de la aplicación. La siguiente función es una función en el enrutador Express que, cuando se invoca, ejecuta el middleware que sucede al middleware actual.

Las funciones de middleware pueden realizar las siguientes tareas:

  • Ejecuta cualquier código.
  • Realice cambios en la solicitud y los objetos de respuesta.
  • Finaliza el ciclo de solicitud-respuesta.
  • Llame al siguiente middleware en la pila.

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á pendiente.

ingrese la descripción de la imagen aquí

Ejemplo

Aquí hay un ejemplo de una sencilla aplicación Express "Hello World". El resto de este artículo definirá y agregará dos funciones de middleware a la aplicación: una llamada myLogger que imprime un mensaje de registro simple y otra llamada requestTime 1 que muestra la marca de tiempo de la solicitud HTTP.

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

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

app.listen(3000)   

Función de middleware myLogger

Aquí hay un ejemplo simple de una función de middleware llamada "myLogger". Esta función simplemente imprime "LOGGED" cuando una solicitud a la aplicación pasa por ella. La función de middleware se asigna a una variable llamada myLogger.

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

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.

Para cargar la función de middleware, llame a app.use () , especificando la función de middleware. Por ejemplo, el siguiente código carga la función de middleware myLogger antes de la ruta a la ruta raíz (/).

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)

Cada vez que la aplicación recibe una solicitud, imprime el mensaje "LOGGED" en el terminal.

El orden de carga del middleware es importante: las funciones de middleware que se cargan primero también se ejecutan primero.

Si myLogger se carga después de la ruta a la ruta raíz, la solicitud nunca llega y la aplicación no imprime "LOGGED", porque el controlador de ruta de la ruta raíz finaliza el ciclo de solicitud-respuesta.

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 () .


  1. Esta publicación solo contendrá el middleware myLogger, para obtener más información, puede ir a la guía expressjs original aquí .

Suraj Jain
fuente
1
Muy buena explicación.
Drumbeg
Está disponible en el sitio express aquí expressjs.com/en/guide/writing-middleware.html , es realmente bueno. Me pregunto por qué nadie lo mencionó hasta ahora.
Suraj Jain
2
Buena esa. Es la explicación más clara que he visto aquí y sí, ¡extraño que nadie lo haya mencionado!
Drumbeg
1
Bien explicado
Rehan Shikkalgar
El orden de carga del middleware es importante: las funciones de middleware que se cargan primero también se ejecutan primero. : Esta es una nota tan importante. Ninguna otra respuesta menciona esto. Para un principiante que ha trabajado solo en python, esto es extremadamente importante, ya que estas cosas podrían nunca haberse encontrado.
Tessaracter
11

===== Explicación muy muy simple =====

Los middlewares a menudo se usan en el contexto del marco Express.js y son un concepto fundamental para node.js. En pocas palabras, es básicamente una función que tiene acceso a los objetos de solicitud y respuesta de su aplicación. La forma en que me gustaría pensarlo es una serie de 'controles / pre-pantallas' que atraviesa la solicitud antes de que la aplicación la maneje. Por ejemplo, Middlewares sería una buena opción para determinar si la solicitud se autentica antes de proceder a la aplicación y devolver la página de inicio de sesión si la solicitud no se autentica o para registrar cada solicitud. Hay muchos middlewares de terceros disponibles que permiten una variedad de funcionalidades.

Ejemplo de middleware simple:

var app = express();
app.use(function(req,res,next)){
    console.log("Request URL - "req.url);
    next();
}

El código anterior se ejecutará para cada solicitud que ingrese y registrará la URL de solicitud, el método next () esencialmente permite que el programa continúe. Si no se invoca la función next (), el programa no continuará más y se detendrá en la ejecución del middleware.

Un par de Middleware Gotchas:

  1. El orden de middlewares en su aplicación es importante, ya que la solicitud pasaría por cada uno en un orden secuencial.
  2. Olvidar llamar al método next () en su función de middleware puede detener el procesamiento de su solicitud.
  3. Cualquier cambio en los objetos req y res en la función de middleware haría que el cambio esté disponible para otras partes de la aplicación que usa req y res
Vaibhav Bacchav
fuente
1
¡Muchas gracias! Esta es la mejor explicación hasta ahora para entender esto. Una pregunta, estoy leyendo un código con middleware y no llama next()pero return next(). ¿Cuál es la diferencia?
KansaiRobot
Muchas gracias amigo por las palabras amables ... lo hacemos next()porque queremos que se llame al próximo middleware, no creo next()o return next(), ¡debería hacer alguna diferencia! Todavía depende de cuál sea el código ...
Vaibhav Bacchav
7

Los middlewares son funciones ejecutadas en el medio después de que la entrada / fuente produce una salida que podría ser la salida final o podría ser utilizada por el siguiente middleware hasta que se complete el ciclo.

Es como un producto que pasa por una línea de ensamblaje donde se modifica a medida que avanza hasta que se completa, se evalúa o se rechaza.

Un middleware espera que funcione algún valor (es decir, valores de parámetros) y, en función de alguna lógica, el middleware llamará o no al siguiente middleware o enviará una respuesta al cliente.

Si aún no puede comprender el concepto de middleware, es similar a los patrones de Decorador o Cadena de comando.

naz
fuente
5

El middleware es un subconjunto de funciones encadenadas llamadas por la capa de enrutamiento Express js antes de que se invoque el controlador definido por el usuario. Las funciones de middleware tienen acceso completo a los objetos de solicitud y respuesta y pueden modificar cualquiera de ellos.

La cadena de middleware siempre se llama en el orden exacto en que se ha definido, por lo que es vital que sepa exactamente qué está haciendo una pieza específica de middleware.
Una vez que finaliza una función de middleware, llama a la siguiente función de la cadena invocando su siguiente argumento como función.
Una vez que se ejecuta la cadena completa, se llama al manejador de solicitudes del usuario.

rishabh dev
fuente
1

¡Mantén las cosas simples, hombre!

Nota: la respuesta está relacionada con los casos de middlware incorporado ExpressJS, sin embargo, existen diferentes definiciones y casos de uso de middlewares.

Desde mi punto de vista, el middleware actúa como funciones de utilidad o ayuda, pero su activación y uso es completamente opcional al usar el app.use('path', /* define or use builtin middleware */)que no quiere que escribamos un código para realizar tareas muy comunes que son necesarias para cada solicitud HTTP de nuestro cliente como procesar cookies, tokens CSRF y ..., que son muy comunes en la mayoría de las aplicaciones, por lo que el middleware puede ayudarnos a hacer todo esto para cada solicitud HTTP de nuestro cliente en alguna pila, secuencia u orden de operaciones y luego proporcionar el resultado del proceso como Una sola unidad de solicitud del cliente .

Ejemplo:

Aceptar la solicitud de los clientes y proporcionarles respuestas de acuerdo con sus solicitudes es la naturaleza de la tecnología del servidor web.

Imagínese si estamos respondiendo simplemente "¡Hola, mundo!" El texto para una solicitud GET HTTP al URI raíz de nuestro servidor web es un escenario muy simple y no necesita nada más, sino que si estamos verificando al usuario actualmente conectado y luego respondemos con "¡Hola, Nombre de usuario!" necesita algo más de lo habitual en este caso, necesitamos un middleware para procesar todos los metadatos de la solicitud del cliente y proporcionarnos la información de identificación tomada de la solicitud del cliente, de acuerdo con esa información podemos identificar de manera única a nuestro usuario actual y es posible responder a él / ella con algunos datos relacionados.

¡Espero que ayude a alguien!

MNR
fuente
-1

En términos muy básicos, si quiero explicarlo de esta manera, aprendo esto en el curso acelerado rápido del canal de YouTube de Traversymedia.
ok, por lo que middleware es una función que se ejecuta después de hacer una llamada a su ruta de esta manera.

var logger = function(req, res, next){
   console.log('logging...');
   next();
}

app.use(logger);

Esta función de registro se ejecuta cada vez que actualiza su página, lo que significa que puede escribir cualquier cosa que necesite hacer después de que su página reciba una llamada API de operación, restablezca las cosas básicamente cualquier cosa. y coloque este middleware antes de que el orden de la función de ruta del middleware sea realmente importante o no funcione

Akshay Vinchurkar
fuente