Écriture d’intergiciels à utiliser dans les applications Express

Aperçu

Les fonctions d’intergiciel sont des fonctions qui ont accès à l’objet requête (req), l’objet de réponse (res), et la fonction next dans le cycle demande-réponse de l’application. La fonction next est une fonction du routeur Express qui, lorsqu’elle est invoquée, exécute l’intergiciel succédant à l’intergiciel actuel.

Les fonctions d’intergiciel peuvent effectuer les tâches suivantes :

  • Exécuter n’importe quel code.
  • Affectuer des modifications à la demande et aux objets de réponse.
  • Faire cesser le cycle demande-réponse.
  • Appeler l’intergiciel suivant dans la pile.

Si la fonction intergiciel actuelle ne fait pas cesser le cycle demande-réponse, elle doit appeler next() pour passer le contrôle à la fonction intergiciel suivante. Sinon, la demande sera laissée en suspens.

La figure suivante montre les éléments d’un appel de fonction intergiciel :

Méthode HTTP pour laquelle la fonction intergiciel s’applique.
Chemin (route) pour lequel la fonction middleware s’applique.
La fonction middleware.
Argument de rappel à la fonction middleware, appelé « next » par convention.
Argument de réponse HTTP à la fonction intergiciel, appelé « res » par convention.
Argument de requête HTTP à la fonction intergiciel, appelé « req » par convention.

Depuis Express 5, les fonctions middleware qui renvoient une Promise appellent next(value) lorsqu’elles rejettent ou jettent une erreur. next sera appelé avec soit la valeur rejetée, soit l’erreur lancée.

Exemple

Voici un exemple d’une simple application Express « Hello World ».La suite de cet article définira et ajoutera trois fonctions middleware à l’application :une appelée myLogger qui imprime un message de journal simple, une appelée requestTime qui affiche l’horodatage de la requête HTTP, et une appelée validateCookies qui valide les cookies entrants.

var express = require('express')var app = express()app.get('/', function (req, res) { res.send('Hello World!')})app.listen(3000)

Fonction middleware myLogger

Voici un exemple simple de fonction middleware appelée « myLogger ». Cette fonction imprime simplement « LOGGED » lorsqu’une requête à l’app passe par elle. La fonction middleware est affectée à une variable nommée myLogger.

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

Notez l’appel ci-dessus à next(). L’appel de cette fonction invoque la fonction middleware suivante dans l’application.La fonction next() ne fait pas partie de l’API Node.js ou Express, mais constitue le troisième argument transmis à la fonction middleware. La fonction next() pourrait porter n’importe quel nom, mais par convention, elle est toujours nommée « next ».Pour éviter toute confusion, utilisez toujours cette convention.

Pour charger la fonction d’intergiciel, appelez app.use(), en spécifiant la fonction d’intergiciel.Par exemple, le code suivant charge la fonction middleware myLogger avant la route vers le chemin racine (/).

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)

Chaque fois que l’application reçoit une requête, elle imprime le message « LOGGED » sur le terminal.

L’ordre de chargement des middlewares est important : les fonctions middlewares qui sont chargées en premier sont également exécutées en premier.

Si myLogger est chargé après la route vers le chemin racine, la requête ne l’atteint jamais et l’app n’imprime pas « LOGGED », car le gestionnaire de route du chemin racine met fin au cycle requête-réponse.

La fonction middleware myLogger imprime simplement un message, puis transmet la demande à la fonction middleware suivante dans la pile en appelant la fonction next().

Fonction middleware requestTime

Puis, nous allons créer une fonction middleware appelée « requestTime » et ajouter une propriété appelée requestTimeà l’objet requête.

var requestTime = function (req, res, next) { req.requestTime = Date.now() next()}

L’application utilise maintenant la fonction middleware requestTime. De plus, la fonction de rappel de la route du chemin racine utilise la propriété que la fonction middleware ajoute à req (l’objet de requête).

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)

Lorsque vous effectuez une requête à la racine de l’appli, celle-ci affiche désormais l’horodatage de votre requête dans le navigateur.

Fonction middleware validateCookies

Enfin, nous allons créer une fonction middleware qui valide les cookies entrants et envoie une réponse 400 si les cookies ne sont pas valides.

Voici un exemple de fonction qui valide les cookies avec un service asynchrone externe.

async function cookieValidator (cookies) { try { await externallyValidateCookie(cookies.testCookie) } catch { throw new Error('Invalid cookies') }}

Ici, nous utilisons le middleware cookie-parser pour analyser les cookies entrants de l’objet req et les transmettre à notre fonction cookieValidator. L’intergiciel validateCookies renvoie une Promise qui, en cas de rejet, déclenchera automatiquement notre gestionnaire d’erreurs.

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)

Notez comment next() est appelée après await cookieValidator(req.cookies). Cela garantit que si cookieValidator se résout, l’intergiciel suivant dans la pile sera appelé. Si vous passez quoi que ce soit à la fonction next() (à l’exception de la chaîne 'route' ou 'router'), Express considère la requête actuelle comme étant une erreur et sautera toutes les fonctions restantes de routage et de middleware ne traitant pas les erreurs.

Parce que vous avez accès à l’objet de requête, à l’objet de réponse, à la fonction d’intergiciel suivante dans la pile et à l’ensemble de l’API Node.js, les possibilités avec les fonctions d’intergiciel sont infinies.

Pour plus d’informations sur les intergiciels Express, voir : Utilisation d’un intergiciel Express.

Un intergiciel configurable

Si vous avez besoin que votre intergiciel soit configurable, exportez une fonction qui accepte un objet d’options ou d’autres paramètres, qui, ensuite, renvoie la mise en œuvre de l’intergiciel en fonction des paramètres d’entrée.

Fichier : my-middleware.js

module.exports = function (options) { return function (req, res, next) { // Implement the middleware function based on the options object next() }}

L’intergiciel peut maintenant être utilisé comme indiqué ci-dessous.

var mw = require('./my-middleware.js')app.use(mw({ option1: '1', option2: '2' }))

Référez-vous à cookie-session et à la compression pour des exemples d’intergiciel configurable.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *