Note de la rédaction – L’article de blog intitulé « Introduction au module JavaScript de NGINX » redirige vers cette page. Cet article a été mis à jour pour inclure les directives et fonctionnalités du module JavaScript de NGINX prises en charge en avril 2021.

Le module JavaScript NGINX (njs) est devenu disponible pour tous en tant que module stable dans NGINX Open Source 1.11.10 et NGINX Plus R12. [À l’origine, le module s’appelait nginScript, et ce nom apparaît dans certains articles plus anciens.] Nous travaillons sans relâche sur NGINX JavaScript depuis son lancement en septembre 2015, en ajoutant les fonctionnalités et la prise en charge du langage incluses dans le module stable.
NGINX JavaScript est une implémentation unique de JavaScript pour NGINX et NGINX Plus, spécialement conçue pour les cas d’usage côté serveur et le traitement de chaque requête. Elle étend la syntaxe de configuration de NGINX avec du code JavaScript afin de mettre en œuvre des solutions de configuration sophistiquées.
Les cas d’utilisation sont nombreux, d’autant plus que le module NGINX JavaScript est disponible pour les protocoles HTTP et TCP/UDP. Voici quelques exemples de cas d’utilisation de NGINX JavaScript :
- Génération de formats de journaux personnalisés avec des valeurs non disponibles dans les variables NGINX standard (par exemple, la journalisation de diagnostic)
- Modification des réponses provenant de serveurs mandataires (filtrage des réponses)
- Mise en œuvre de mécanismes d’authentification personnalisés (par exemple, l’introspection de jetons OAuth 2.0)
- Analyse des protocoles TCP/UDP pour assurer la persistance des sessions au niveau applicatif (par exemple, l’équilibrage de charge MQTT)
Avant d’aborder NGINX JavaScript plus en détail, commençons par clarifier deux idées reçues courantes.
NGINX JavaScript n’est pas Lua
Au fil des ans, la communauté NGINX a créé plusieurs extensions programmatiques. À l’heure où nous écrivons ces lignes, Lua est la plus populaire d’entre elles. Elle est disponible sous la forme d’un module pour NGINX et d’un module dynamique tiers précompilé et pris en charge pour NGINX Plus. Le module Lua et les bibliothèques complémentaires offrent une intégration étroite avec le cœur de NGINX ainsi qu’un riche éventail de fonctionnalités, notamment un pilote pour Redis.
Lua est un langage de script puissant. Son adoption reste toutefois assez limitée et il ne fait généralement pas partie de la « boîte à outils de compétences » des développeurs frontend ou des ingénieurs DevOps.
NGINX JavaScript ne vise pas à remplacer Lua, et il faudra encore du temps avant qu’il n’offre un niveau de fonctionnalités comparable. L’objectif de NGINX JavaScript est de proposer des solutions de configuration programmatique au plus grand nombre grâce à l’utilisation d’un langage de programmation populaire.
NGINX JavaScript n’est pas Node.js
NGINX JavaScript n’a pas vocation à transformer NGINX ou NGINX Plus en serveur d’applications. En termes simples, les cas d’utilisation de NGINX JavaScript s’apparentent à ceux d’un middleware, car l’exécution du code JavaScript intervient entre le client et le contenu. D’un point de vue technique, bien que Node.js ait deux points communs avec l’association de NGINX JavaScript et de NGINX ou NGINX Plus : une architecture événementielle et le langage de programmation JavaScript, les similitudes s’arrêtent là.
Node.js utilise le moteur JavaScript V8 de Google, tandis que NGINX JavaScript est une implémentation sur mesure des normes ECMAScript, conçue spécifiquement pour NGINX et NGINX Plus. Node.js conserve en mémoire une machine virtuelle JavaScript (VM) persistante et effectue régulièrement un ramasse-miettes pour gérer la mémoire, tandis que NGINX JavaScript initialise une nouvelle VM JavaScript et alloue la mémoire nécessaire pour chaque requête, puis libère cette mémoire une fois la requête traitée.
JavaScript en tant que langage côté serveur
Comme indiqué précédemment, NGINX JavaScript est une implémentation sur mesure du langage JavaScript. Tous les autres moteurs d’exécution JavaScript existants sont conçus pour fonctionner dans un navigateur web. La nature de l’exécution du code côté client diffère de celle du code côté serveur à bien des égards, qu’il s’agisse de la disponibilité des ressources système ou du nombre potentiel d’environnements d’exécution simultanés.
Nous avons décidé de développer notre propre environnement d’exécution JavaScript afin de répondre aux exigences de l’exécution de code côté serveur et de l’intégrer harmonieusement à l’architecture de traitement des requêtes de NGINX. Les principes de conception de NGINX JavaScript sont les suivants :
- L’environnement d’exécution naît et disparaît avec la requêteLe module NGINX JavaScript exécute le bytecode dans un seul thread afin de permettre une initialisation et une libération rapides. L’environnement d’exécution est initialisé pour chaque requête. Le démarrage est extrêmement rapide, car aucun état complexe ni aucun utilitaire ne doit être initialisé. Pendant l’exécution, la mémoire est allouée dans des pools, puis libérée à la fin en supprimant ces pools. Ce mode de gestion de la mémoire évite d’avoir à suivre et à libérer chaque objet individuellement ou à utiliser un ramasse-miettes.
- Exécution de code non bloquanteLe modèle événementiel de NGINX et NGINX Plus planifie l’exécution de chaque environnement d’exécution NGINX JavaScript. Lorsqu’une règle NGINX JavaScript effectue une opération bloquante (telle que la lecture de données réseau ou l’émission d’une sous-requête externe), NGINX et NGINX Plus suspendent de manière transparente l’exécution de la machine virtuelle NGINX JavaScript associée et la replanifient une fois l’événement terminé. Vous pouvez ainsi écrire des règles de manière simple et linéaire, tandis que NGINX et NGINX Plus planifient leur exécution sans blocage interne.
- Implémentation limitée aux fonctionnalités du langage dont nous avons besoinLes spécifications de JavaScript sont définies par les normes ECMAScript. NGINX JavaScript est conforme à ECMAScript 5.1 et intègre certaines fonctionnalités d’ECMAScript 6 pour les fonctions mathématiques. Le fait d’implémenter notre propre environnement d’exécution JavaScript nous permet de donner la priorité aux fonctionnalités du langage adaptées aux cas d’utilisation côté serveur et d’ignorer celles dont nous n’avons pas besoin. Nous tenons à jour une liste des éléments du langage actuellement pris en charge.
- Intégration étroite avec les phases de traitement des requêtesNGINX et NGINX Plus traitent les requêtes en plusieurs phases distinctes. Les directives de configuration interviennent généralement lors d’une phase précise, et les modules NGINX natifs tirent souvent parti de la possibilité d’examiner ou de modifier une requête à une phase donnée. NGINX JavaScript expose certaines phases de traitement au moyen de directives de configuration, ce qui permet de contrôler le moment où le code JavaScript est exécuté. Cette intégration à la syntaxe de configuration allie la puissance et la flexibilité des modules NGINX natifs à la simplicité du code JavaScript. Le tableau ci-dessous indique les phases de traitement accessibles via NGINX JavaScript au moment de la rédaction, ainsi que les directives de configuration correspondantes.
| Phase de traitement | Module HTTP | Module Stream |
|---|---|---|
Accès – Authentification et contrôle d’accès | auth_request et js_content | js_access |
Prélecture – Lecture/écriture de la charge utile | N/A | js_preread |
Filtrage – Lecture/écriture de la réponse lors du traitement par le proxy | js_body_filterjs_header_filter | js_filter |
Contenu – Envoi de la réponse au client | js_content | N/A |
Journalisation / Variables – Évaluation à la demande | js_set | js_set |
Bien démarrer avec NGINX JavaScript : un exemple concret
NGINX JavaScript est implémenté sous la forme d’un module que vous pouvez compiler dans un binaire NGINX Open Source ou charger dynamiquement dans NGINX ou NGINX Plus. Instructions pour activer NGINX JavaScript avec NGINX et NGINX Plus figurent à la fin de cet article.
Dans cet exemple, nous utilisons NGINX ou NGINX Plus comme simple proxy inverse et NGINX JavaScript pour créer des entrées de journal d’accès dans un format spécialisé qui :
- Inclut les en-têtes de requête envoyés par le client
- Inclut les en-têtes de réponse renvoyés par le backend
- Utilise des paires clé-valeur pour une ingestion et une recherche efficaces avec des outils de traitement des journaux tels que la pile ELK (désormais appelée Elastic Stack), Graylog et Splunk
La configuration de NGINX pour cet exemple est extrêmement simple.
Chargement de l’exemple de code…
Comme vous pouvez le constater, le code JavaScript NGINX n’est pas intégré directement à la syntaxe de configuration. Nous utilisons plutôt la directive js_import pour spécifier le fichier qui contient l’ensemble de notre code JavaScript. La directive js_set définit une nouvelle variable NGINX, $access_log_headers, ainsi que la fonction JavaScript qui lui attribue une valeur. La directive log_format définit un nouveau format appelé kvpairs, qui écrit chaque ligne du journal avec la valeur de $access_log_headers.
Le bloc server définit un simple proxy inverse HTTP qui transmet toutes les requêtes à https://www.example.com. La directive access_log indique que toutes les requêtes seront journalisées au format kvpairs.
Examinons maintenant le code JavaScript qui prépare une entrée de journal.
Chargement de l’exemple de code…
La valeur renvoyée par la fonction kvAccess — une entrée de journal — est transmise à la directive de configuration js_set dans rawheader_logging.conf. Gardez à l’esprit que les variables NGINX sont évaluées à la demande, ce qui signifie que la fonction JavaScript définie par js_set est exécutée lorsque la valeur de la variable est requise. Dans cet exemple, $access_log_headers est utilisée dans la directive log_format, de sorte que kvAccess() est exécutée au moment de la journalisation. Les variables utilisées dans les directives map ou rewrite (non illustrées dans cet exemple) déclenchent l’exécution du code JavaScript correspondant à une phase antérieure du traitement.
Nous pouvons voir cette solution de journalisation NGINX enrichie par JavaScript à l’œuvre en faisant transiter une requête par notre proxy inverse et en observant l’entrée correspondante dans le fichier journal, qui inclut les en-têtes de requête avec le préfixe « in. » et les en-têtes de réponse avec le préfixe « out. ».
$ curl http://127.0.0.1/$ tail --lines=1 /var/log/nginx/access_headers.log2021-04-23T10:08:15+00:00 client=172.17.0.1 method=GET uri=/index.html status=200 in.Host=localhost:55081 in.User-Agent=curl/7.64.1 in.Accept=*/* out.Content-Type=text/html out.Content-Length=612 out.ETag=x22606339ef-264x22 out.Accept-Ranges=bytesL’utilité de NGINX JavaScript tient en grande partie à son accès aux mécanismes internes de NGINX. Cet exemple utilise plusieurs propriétés de l’objet de requête (r). Le module Stream de NGINX JavaScript (pour les applications TCP et UDP) utilise un objet de session (s) doté de son propre ensemble de propriétés. Pour découvrir d’autres exemples de solutions NGINX JavaScript pour HTTP et TCP/UDP, consultez Cas d’utilisation du module NGINX JavaScript.
Nous serions ravis de découvrir les cas d’usage que vous imaginez pour NGINX JavaScript. N’hésitez pas à nous en faire part dans la section des commentaires ci-dessous.
Cas d’utilisation du module JavaScript NGINX
Consultez ces articles de blog pour découvrir d’autres cas d’utilisation HTTP et TCP/UDP du module JavaScript NGINX :
- Déclaration de code JavaScript et de variables dans des contextes locaux dans « Rendez votre configuration NGINX encore plus modulaire et réutilisable avec njs 0.7.7 »
- Utiliser NGINX comme passerelle DoT ou DoH
- Annonce de NGINX Plus R26 – Utilisation de fonctions asynchrones et de l’API WebCrypto pour générer des nombres aléatoires sécurisés et hacher des chaînes de texte
- Atténuer la vulnérabilité log4j avec NGINX
- Journalisation avancée avec le module JavaScript de NGINX dans « Mise à l’échelle de MySQL avec l’équilibrage de charge TCP et Galera Cluster »
- Annonce de NGINX Plus R24 – Filtrage des réponses, tant au niveau du corps que des en-têtes ; utilisation d’un client HTTP intégré pour authentifier les connexions TCP/UDP
- Validation des corps de requête dans « Déploiement de NGINX Plus en tant que passerelle API, partie 2 : protection des services backend »
- Journalisation des diagnostics avec le module JavaScript NGINX<.htmla>
- Annonce de NGINX Plus R22 – Journalisation de l’ensemble exact des en-têtes envoyés par le client chaque fois qu’une erreur se produit
- Annonce de NGINX Plus R21 – Enchaînement de sous-requêtes dans une même séquence de code sans utiliser de fonctions de rappel ; envoi d’une copie des en-têtes de requête à un système de gestion des informations et des événements de sécurité (SIEM)
- Un seul POST : activer le DNS déclaratif avec F5 et le module JavaScript NGINX
- Extension de
auth_requestavec le module JavaScript NGINX dans « Validation des jetons d’accès OAuth 2.0 avec NGINX et NGINX Plus » - Mises à jour à distance des appareils IoT avec NGINX
- Annonce de NGINX Plus R18 – Journalisation d’une version hachée (masquée) de l’adresse IP du client au lieu de l’adresse réelle
- Application de correctifs virtuels avec le module JavaScript NGINX
- Regroupement des requêtes API avec NGINX Plus et le module JavaScript NGINX
- Annonce de NGINX Plus R15 – Envoi simultané d’une requête HTTP à deux backends différents, puis transmission de la première réponse et abandon de la seconde ; ajout de l’intégrité des données aux cookies de l’application
- Mise à l’échelle de la détection des modifications grâce au hachage JavaScript dans « Détection de la défiguration d’une page d’accueil à l’aide de contrôles d’intégrité actifs »
- Extension de l’équilibrage de charge TCP.htmlUDP avec nginScript dans « Équilibrage de charge TCP/UDP avec NGINX : présentation, conseils et astuces »
- Utilisation de certificats clients pour authentifier les clients MQTT dans « NGINX Plus pour l’IoT : chiffrement et authentification du trafic MQTT »
- Équilibrage de charge MQTT pour la persistance des sessions avec le module JavaScript NGINX dans « NGINX Plus pour l’IoT : équilibrage de charge MQTT »
- Masquage des données pour protéger la vie privée des utilisateurs avec le module JavaScript de NGINX
- Présentation de NGINX Plus R11 – Recherche de motifs clés dans un message au sein d’un flux du protocole MySQL afin d’identifier l’opération SQL
- Utiliser le module JavaScript de NGINX pour migrer progressivement les clients vers un nouveau serveur
[ngx_snippet name=’njs-enable-instructions’]
À propos de l’auteur

Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.
Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.
Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.
Caches partagés avec les clusters de cache NGINX Plus, partie 1
Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.
Introduction aux microservices
Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.