Aprovecha la potencia y la comodidad de JavaScript en cada solicitud con el módulo JavaScript de NGINX

NGINX | 23 de abril de 2021

Editor – La entrada de blog titulada «Introducción al módulo JavaScript de NGINX» redirige aquí. La entrada se ha actualizado con las directivas y funcionalidades del módulo JavaScript de NGINX compatibles a fecha de abril de 2021.

El módulo JavaScript de NGINX (njs) pasó a estar disponible de forma general como módulo estable en NGINX Open Source 1.11.10 y NGINX Plus R12. [El módulo se llamaba originalmente nginScript, y ese nombre aparece en algunas publicaciones antiguas.] Hemos trabajado de forma constante en NGINX JavaScript desde su lanzamiento en septiembre de 2015, incorporando las funcionalidades y la compatibilidad con el lenguaje incluidas en el módulo estable.

NGINX JavaScript es una implementación única de JavaScript para NGINX y NGINX Plus, diseñada específicamente para casos de uso del lado del servidor y el procesamiento de cada solicitud. Amplía la sintaxis de configuración de NGINX con código JavaScript para implementar soluciones de configuración avanzadas.

Los casos de uso son numerosos, especialmente porque el módulo NGINX JavaScript está disponible tanto para HTTP como para los protocolos TCP/UDP. Algunos ejemplos de casos de uso de NGINX JavaScript son:

Antes de analizar NGINX JavaScript con más detalle, aclaremos primero dos ideas erróneas habituales.

NGINX JavaScript no es Lua

La comunidad de NGINX ha creado varias extensiones programáticas a lo largo de los años. En el momento de redactar este texto, Lua es la más popular; está disponible como un módulo para NGINX y como un módulo dinámico de terceros precompilado y con soporte para NGINX Plus. El módulo de Lua y las bibliotecas complementarias ofrecen una estrecha integración con el núcleo de NGINX y un amplio conjunto de funcionalidades, incluido un controlador para Redis.

Lua es un potente lenguaje de scripting. Sin embargo, su adopción sigue siendo bastante minoritaria y no suele formar parte del «conjunto de competencias» de los desarrolladores frontend ni de los ingenieros de DevOps.

NGINX JavaScript no pretende sustituir a Lua y aún pasará algún tiempo antes de que NGINX JavaScript alcance un nivel de funcionalidad comparable. El objetivo de NGINX JavaScript es ofrecer soluciones de configuración programática a la comunidad más amplia posible mediante el uso de un lenguaje de programación popular.

NGINX JavaScript no es Node.js

NGINX JavaScript no pretende convertir NGINX ni NGINX Plus en un servidor de aplicaciones. En pocas palabras, los casos de uso de NGINX JavaScript son similares a los del middleware, ya que la ejecución del código JavaScript tiene lugar entre el cliente y el contenido. Desde un punto de vista técnico, aunque Node.js comparte dos aspectos con la combinación de NGINX JavaScript y NGINX o NGINX Plus —una arquitectura basada en eventos y el lenguaje de programación JavaScript—, las similitudes terminan ahí.

Node.js utiliza el motor de JavaScript V8 de Google, mientras que NGINX JavaScript es una implementación específica de los estándares ECMAScript, diseñada expresamente para NGINX y NGINX Plus. Node.js mantiene en memoria una máquina virtual (VM) de JavaScript persistente y realiza periódicamente la recolección de elementos no utilizados para gestionar la memoria, mientras que NGINX JavaScript inicializa una nueva VM de JavaScript y la memoria necesaria para cada solicitud, y libera la memoria cuando esta finaliza.

JavaScript como lenguaje del lado del servidor

Como se ha mencionado anteriormente, NGINX JavaScript es una implementación específica del lenguaje JavaScript. Todos los demás motores de ejecución de JavaScript existentes están diseñados para ejecutarse en un navegador web. La naturaleza de la ejecución de código del lado del cliente difiere de la ejecución de código del lado del servidor en muchos aspectos, desde la disponibilidad de recursos del sistema hasta el posible número de entornos de ejecución simultáneos.

Decidimos implementar nuestro propio entorno de ejecución de JavaScript para satisfacer los requisitos de la ejecución de código en el servidor e integrarlo de forma elegante en la arquitectura de procesamiento de solicitudes de NGINX. Estos son nuestros principios de diseño para NGINX JavaScript:

  • El entorno de ejecución nace y muere con la solicitudEl módulo JavaScript de NGINX utiliza la ejecución de bytecode en un único hilo, diseñada para permitir una inicialización y una eliminación rápidas. El entorno de ejecución se inicializa para cada solicitud. El arranque es extremadamente rápido, ya que no hay ningún estado complejo ni funciones auxiliares que inicializar. Durante la ejecución, la memoria se acumula en bloques y, al finalizar, se libera eliminando dichos bloques. Este sistema de gestión de memoria evita tener que realizar un seguimiento de cada objeto y liberarlo individualmente, así como utilizar un recolector de basura.
  • Ejecución de código sin bloqueoEl modelo basado en eventos de NGINX y NGINX Plus programa la ejecución de cada entorno de ejecución de NGINX JavaScript. Cuando una regla de NGINX JavaScript realiza una operación de bloqueo (como leer datos de red o emitir una subsolicitud externa), NGINX y NGINX Plus suspenden de forma transparente la ejecución de la máquina virtual de NGINX JavaScript asociada y la reprograman cuando finaliza el evento. Esto permite escribir reglas de forma sencilla y lineal, mientras NGINX y NGINX Plus las programan sin bloqueos internos.
  • Implementar únicamente la compatibilidad con el lenguaje que necesitamosLas especificaciones de JavaScript están definidas por los estándares ECMAScript. NGINX JavaScript sigue ECMAScript 5.1 e incorpora algunas características de ECMAScript 6 para funciones matemáticas. Implementar nuestro propio entorno de ejecución de JavaScript nos permite priorizar la compatibilidad con el lenguaje para casos de uso del lado del servidor e ignorar lo que no necesitamos. Mantenemos una lista de los elementos del lenguaje compatibles actualmente.
  • Integración estrecha con las fases de procesamiento de solicitudesNGINX y NGINX Plus procesan las solicitudes en distintas fases. Las directivas de configuración suelen actuar en una fase específica, y los módulos nativos de NGINX a menudo aprovechan la posibilidad de inspeccionar o modificar una solicitud en una fase determinada. NGINX JavaScript expone algunas de las fases de procesamiento mediante directivas de configuración para permitir controlar cuándo se ejecuta el código JavaScript. Esta integración con la sintaxis de configuración ofrece la potencia y flexibilidad de los módulos nativos de NGINX con la sencillez del código JavaScript. La tabla siguiente indica qué fases de procesamiento están disponibles mediante NGINX JavaScript en el momento de redactar este texto y las directivas de configuración que permiten acceder a ellas.
Fase de procesamientoMódulo HTTPMódulo Stream
Acceso – Autenticación y control de accesoauth_request y js_contentjs_access
Lectura previa – Lectura/escritura de la carga útilN/Djs_preread
Filtrado – Lectura/escritura de la respuesta durante el proxyjs_body_filter
js_header_filter
js_filter
Contenido – Envío de la respuesta al clientejs_contentN/D
Registro / Variables – Evaluación bajo demandajs_setjs_set

Primeros pasos con NGINX JavaScript – Un ejemplo real

NGINX JavaScript se implementa como un módulo que puede compilar en un binario de NGINX Open Source o cargar dinámicamente en NGINX o NGINX Plus. Instrucciones para habilitar NGINX JavaScript con NGINX y NGINX Plus se encuentran al final de este artículo.

En este ejemplo, utilizamos NGINX o NGINX Plus como un proxy inverso sencillo y NGINX JavaScript para crear entradas del registro de acceso en un formato especializado que:

  • Incluye las cabeceras de solicitud enviadas por el cliente
  • Incluye las cabeceras de respuesta devueltas por el backend
  • Utiliza pares clave-valor para facilitar una ingesta y búsqueda eficientes con herramientas de procesamiento de registros como ELK Stack (ahora denominada Elastic Stack), Graylog y Splunk

La configuración de NGINX para este ejemplo es extremadamente sencilla.

Cargando ejemplo de código…

Como puede ver, el código JavaScript de NGINX no se incluye directamente en la sintaxis de configuración. En su lugar, utilizamos la directiva js_import para especificar el archivo que contiene todo nuestro código JavaScript. La directiva js_set define una nueva variable de NGINX, $access_log_headers, y la función JavaScript que la rellena. La directiva log_format define un nuevo formato denominado kvpairs, que escribe cada línea del registro con el valor de $access_log_headers.

El bloque server define un proxy inverso HTTP sencillo que reenvía todas las solicitudes a https://www.example.com. La directiva access_log especifica que todas las solicitudes se registrarán con el formato kvpairs.

Veamos ahora el código JavaScript que prepara una entrada de registro.

Cargando ejemplo de código…

El valor devuelto por la función kvAccess —una entrada de registro— se pasa a la directiva de configuración js_set en rawheader_logging.conf. Tenga en cuenta que las variables de NGINX se evalúan bajo demanda, lo que a su vez significa que la función JavaScript definida mediante js_set se ejecuta cuando se necesita el valor de la variable. En este ejemplo, $access_log_headers se utiliza en la directiva log_format, por lo que kvAccess() se ejecuta en el momento de registrar la entrada. Las variables utilizadas como parte de las directivas map o rewrite (que no se muestran en este ejemplo) activan la ejecución del código JavaScript correspondiente en una fase anterior del procesamiento.

Podemos ver en acción esta solución de registro de NGINX mejorada con JavaScript enviando una solicitud a través de nuestro proxy inverso y observando la entrada resultante en el archivo de registro, que incluye las cabeceras de la solicitud con el prefijo «in.» y las cabeceras de la respuesta con el prefijo «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=bytes

Gran parte de la utilidad de NGINX JavaScript se debe a su acceso a los componentes internos de NGINX. Este ejemplo utiliza varias propiedades del objeto de solicitud (r). El módulo Stream de NGINX JavaScript (para aplicaciones TCP y UDP) utiliza un objeto de sesión (s) con su propio conjunto de propiedades. Para ver otros ejemplos de soluciones de NGINX JavaScript tanto para HTTP como para TCP/UDP, consulte Casos de uso del módulo JavaScript de NGINX.

Nos encantaría conocer los casos de uso que se os ocurran para NGINX JavaScript. Contádnoslos en la sección de comentarios que aparece a continuación.

Casos de uso del módulo JavaScript de NGINX

Consulta estas entradas de blog para descubrir otros casos de uso de HTTP y TCP/UDP para el módulo JavaScript de NGINX:

[ngx_snippet name=’njs-enable-instructions’]


Compartir
Etiquetas: F5 NGINX, 2021, Tech

Sobre el autor

Liam Crilly
Liam CrillyDirector sénior de Gestión de Producto

Más artículos de Liam Crilly

Artículos relacionados del blog

Únete a F5 NGINX en AppWorld 2024
NGINX | 04/01/2024

Únete a F5 NGINX en AppWorld 2024

Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
NGINX | 26/09/2023

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source

La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.

Exposición de APIs en Kubernetes
NGINX | 10/03/2022

Exposición de APIs en Kubernetes

La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
NGINX | 23/08/2021

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto

Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.

Presentamos NGINX Plus R22
NGINX | 09/06/2020

Presentamos NGINX Plus R22

NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.

Presentamos NGINX Plus R17
NGINX | 11/12/2018

Presentamos NGINX Plus R17

NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.