Resumen
Las funciones de middleware son funciones que tienen acceso al objeto request (req
), el objeto de respuesta (res
), y la función next
en el ciclo solicitud-respuesta de la aplicación. La función next
es una función en el router Express que, al ser invocada, ejecuta el middleware que sucede al middleware actual.
Las funciones del middleware pueden realizar las siguientes tareas:
- Ejecutar cualquier código.
- Hacer cambios en los objetos de petición y respuesta.
- Finalizar el ciclo petición-respuesta.
- Llamar al siguiente middleware de la pila.
Si la función middleware actual no finaliza el ciclo petición-respuesta, debe llamar a next()
para pasar el control a la siguiente función middleware. En caso contrario, la petición quedará colgada.
La siguiente figura muestra los elementos de una llamada a una función middleware:
Método HTTP para el que se aplica la función middleware.
Ruta para la que se aplica la función de middleware.
La función de middleware.
Argumento de devolución de la función de middleware, llamado «next» por convención.
Argumento de respuesta HTTP a la función middleware, llamado «res» por convención.
Argumento de solicitud HTTP a la función middleware, llamado «req» por convención.
|
|
A partir de Express 5, las funciones de middleware que devuelven una Promise llamarán a next(value)
cuando rechacen o lancen un error. next
será llamado con el valor rechazado o con el error lanzado.
Ejemplo
Aquí hay un ejemplo de una simple aplicación Express «Hello World».El resto de este artículo definirá y añadirá tres funciones de middleware a la aplicación: una llamada myLogger
que imprime un simple mensaje de registro, una llamada requestTime
que muestra la marca de tiempo de la petición HTTP, y una llamada validateCookies
que valida las cookies entrantes.
var express = require('express')var app = express()app.get('/', function (req, res) { res.send('Hello World!')})app.listen(3000)
Función middleware myLogger
Aquí tienes un ejemplo sencillo de una función middleware llamada «myLogger». Esta función sólo imprime «LOGGED» cuando una petición a la app pasa por ella. La función middleware se asigna a una variable llamada myLogger
.
var myLogger = function (req, res, next) { console.log('LOGGED') next()}
Nota la llamada anterior a next()
. Al llamar a esta función se invoca la siguiente función de middleware en la app.La función next()
no forma parte de la API de Node.js o Express, sino que es el tercer argumento que se pasa a la función de middleware. La función next()
podría llamarse de cualquier manera, pero por convención siempre se llama «next».Para evitar confusiones, utiliza siempre esta convención.
Para cargar la función middleware, llama a app.use()
, especificando la función 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 app recibe una petición, 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 petición nunca llega a ella y la app no imprime «LOGGED», porque el manejador de ruta de la ruta raíz termina el ciclo petición-respuesta.
La función de middleware myLogger
simplemente imprime un mensaje, y luego pasa la petición a la siguiente función de middleware en la pila llamando a la función next()
.
Función middleware requestTime
A continuación, crearemos una función middleware llamada «requestTime» y añadiremos una propiedad llamada requestTime
al objeto request.
var requestTime = function (req, res, next) { req.requestTime = Date.now() next()}
La app ahora utiliza la función de middleware requestTime
. Además, la función callback de la ruta raíz utiliza la propiedad que la función middleware añade a req
(el objeto de la petición).
var express = require('express')var app = express()var requestTime = function (req, res, next) { req.requestTime = Date.now() next()}app.use(requestTime)app.get('/', function (req, res) { var responseText = 'Hello World!<br>' responseText += '<small>Requested at: ' + req.requestTime + '</small>' res.send(responseText)})app.listen(3000)
Cuando haces una petición a la raíz de la app, ésta ahora muestra la marca de tiempo de tu petición en el navegador.
Función middleware validateCookies
Por último, crearemos una función middleware que valide las cookies entrantes y envíe una respuesta 400 si las cookies no son válidas.
Aquí tenemos una función de ejemplo que valida las cookies con un servicio asíncrono externo.
async function cookieValidator (cookies) { try { await externallyValidateCookie(cookies.testCookie) } catch { throw new Error('Invalid cookies') }}
Aquí utilizamos el cookie-parser
middleware para analizar las cookies entrantes del objeto req
y pasarlas a nuestra función cookieValidator
. El validateCookies
middleware devuelve una Promise que al ser rechazada activará automáticamente nuestro manejador de errores.
var express = require('express')var cookieParser = require('cookie-parser')var cookieValidator = require('./cookieValidator')var app = express()async function validateCookies (req, res, next) { await cookieValidator(req.cookies) next()}app.use(cookieParser())app.use(validateCookies)// error handlerapp.use(function (err, req, res, next) { res.status(400).send(err.message)})app.listen(3000)
Nota cómo next()
se llama después de await cookieValidator(req.cookies)
. Esto asegura que si cookieValidator
se resuelve, se llamará al siguiente middleware de la pila. Si pasas cualquier cosa a la función next()
(excepto la cadena 'route'
o 'router'
), Express considera que la petición actual es un error y se saltará cualquier función restante de enrutamiento y middleware que no sea de gestión de errores.
Debido a que tienes acceso al objeto de solicitud, al objeto de respuesta, a la siguiente función de middleware en la pila y a toda la API de Node.js, las posibilidades con las funciones de middleware son infinitas.
Para más información sobre el middleware de Express, consulta: Usando el middleware Express.
Middleware configurable
Si necesitas que tu middleware sea configurable, exporta una función que acepte un objeto de opciones u otros parámetros, la cual, devuelve la implementación del middleware basada en los parámetros de entrada.
Archivo: my-middleware.js
module.exports = function (options) { return function (req, res, next) { // Implement the middleware function based on the options object next() }}
El middleware ahora puede ser utilizado como se muestra a continuación.
var mw = require('./my-middleware.js')app.use(mw({ option1: '1', option2: '2' }))
Referirse a cookie-session y compresión para ejemplos de middleware configurable.