Editor – A publicação do blog intitulada “Introdução ao módulo JavaScript do NGINX” redireciona para esta página. A publicação foi atualizada com as diretivas e os recursos do módulo JavaScript do NGINX compatíveis até abril de 2021.

O módulo JavaScript do NGINX (njs) passou a estar disponível para uso geral como um módulo estável no NGINX Open Source 1.11.10 e no NGINX Plus R12. [Originalmente, o módulo se chamava nginScript, e esse nome aparece em algumas publicações mais antigas.] Temos trabalhado continuamente no NGINX JavaScript desde seu lançamento em setembro de 2015, adicionando os recursos e o suporte a linguagens incluídos no módulo estável.
O NGINX JavaScript é uma implementação exclusiva de JavaScript para NGINX e NGINX Plus, desenvolvida especificamente para casos de uso no lado do servidor e processamento por solicitação. Ele estende a sintaxe de configuração do NGINX com código JavaScript para implementar soluções de configuração sofisticadas.
Os casos de uso são abrangentes, especialmente porque o módulo NGINX JavaScript está disponível para os protocolos HTTP e TCP/UDP. Alguns exemplos de casos de uso do NGINX JavaScript incluem:
- Geração de formatos de log personalizados com valores não disponíveis nas variáveis padrão do NGINX (por exemplo, logs de diagnóstico)
- Modificação de respostas de servidores com proxy (filtragem de respostas)
- Implementação de esquemas de autenticação personalizados (por exemplo, introspecção de token OAuth 2.0)
- Análise de protocolos TCP/UDP para sessões persistentes no nível da aplicação (por exemplo, balanceamento de carga MQTT)
Antes de abordarmos o NGINX JavaScript em mais detalhes, vamos primeiro esclarecer dois equívocos comuns.
NGINX JavaScript não é Lua
A comunidade do NGINX criou várias extensões programáticas ao longo dos anos. No momento da redação deste texto, Lua é a mais popular delas; ela está disponível como um módulo para NGINX e como um módulo dinâmico de terceiros pré-compilado e com suporte para NGINX Plus. O módulo Lua e as bibliotecas complementares oferecem uma integração profunda com o núcleo do NGINX e um amplo conjunto de funcionalidades, incluindo um driver para Redis.
Lua é uma linguagem de script poderosa. No entanto, sua adoção ainda é bastante restrita, e ela normalmente não faz parte do “conjunto de habilidades” de desenvolvedores de frontend ou engenheiros de DevOps.
O NGINX JavaScript não pretende substituir a Lua, e ainda levará algum tempo até que ofereça um nível de funcionalidade comparável. O objetivo do NGINX JavaScript é fornecer soluções de configuração programática à comunidade mais ampla possível, usando uma linguagem de programação popular.
NGINX JavaScript não é Node.js
O NGINX JavaScript não tem como objetivo transformar o NGINX ou o NGINX Plus em um servidor de aplicações. Em termos simples, os casos de uso do NGINX JavaScript são semelhantes aos de um middleware, pois a execução do código JavaScript ocorre entre o cliente e o conteúdo. Tecnicamente falando, embora o Node.js tenha duas coisas em comum com a combinação do NGINX JavaScript com o NGINX ou o NGINX Plus – uma arquitetura orientada a eventos e a linguagem de programação JavaScript –, as semelhanças terminam aí.
O Node.js usa o mecanismo JavaScript V8 do Google, enquanto o NGINX JavaScript é uma implementação personalizada dos padrões ECMAScript, desenvolvida especificamente para o NGINX e o NGINX Plus. O Node.js mantém uma máquina virtual (VM) JavaScript persistente na memória e realiza a coleta de lixo rotineiramente para gerenciar a memória, enquanto o NGINX JavaScript inicializa uma nova VM JavaScript e aloca a memória necessária para cada solicitação, liberando-a quando a solicitação é concluída.
JavaScript como linguagem do lado do servidor
Como mencionado acima, o NGINX JavaScript é uma implementação personalizada da linguagem JavaScript. Todos os outros mecanismos de execução JavaScript existentes foram projetados para serem executados em um navegador da Web. A natureza da execução de código no lado do cliente difere da execução no lado do servidor em muitos aspectos — desde a disponibilidade de recursos do sistema até o possível número de ambientes de execução simultâneos.
Decidimos implementar nosso próprio ambiente de execução JavaScript para atender aos requisitos da execução de código no lado do servidor e integrá-lo de forma elegante à arquitetura de processamento de requisições do NGINX. Estes são os nossos princípios de design para o NGINX JavaScript:
- O ambiente de execução nasce e morre com a requisiçãoO módulo NGINX JavaScript usa a execução de bytecode em uma única thread, projetada para inicialização e descarte rápidos. O ambiente de execução é inicializado a cada requisição. A inicialização é extremamente rápida, pois não há estados complexos nem recursos auxiliares a serem inicializados. Durante a execução, a memória é acumulada em pools e, ao final, liberada por meio da liberação desses pools. Esse esquema de gerenciamento de memória elimina a necessidade de rastrear e liberar objetos individualmente ou de usar um coletor de lixo.
- Execução de código sem bloqueioO modelo orientado a eventos do NGINX e do NGINX Plus agenda a execução de ambientes de runtime individuais do NGINX JavaScript. Quando uma regra do NGINX JavaScript realiza uma operação de bloqueio (como ler dados da rede ou emitir uma subsolicitação externa), o NGINX e o NGINX Plus suspendem de forma transparente a execução da VM do NGINX JavaScript associada e a reagendam quando o evento é concluído. Isso significa que você pode escrever regras de maneira simples e linear, e o NGINX e o NGINX Plus as agendam sem bloqueio interno.
- Implementar apenas o suporte à linguagem de que precisamosAs especificações do JavaScript são definidas pelos padrões ECMAScript. O NGINX JavaScript segue o ECMAScript 5.1 com alguns recursos do ECMAScript 6 para funções matemáticas. Implementar nosso próprio ambiente de execução JavaScript nos dá a liberdade de priorizar o suporte à linguagem para casos de uso no lado do servidor e ignorar o que não é necessário. Mantemos uma lista dos elementos da linguagem atualmente compatíveis.
- Integração estreita com as fases de processamento de solicitaçõesO NGINX e o NGINX Plus processam solicitações em fases distintas. As diretivas de configuração normalmente operam em uma fase específica, e os módulos nativos do NGINX frequentemente aproveitam a capacidade de inspecionar ou modificar uma solicitação em determinada fase. O NGINX JavaScript disponibiliza algumas das fases de processamento por meio de diretivas de configuração, permitindo controlar quando o código JavaScript é executado. Essa integração com a sintaxe de configuração oferece a potência e a flexibilidade dos módulos nativos do NGINX com a simplicidade do código JavaScript. A tabela abaixo indica quais fases de processamento podem ser acessadas por meio do NGINX JavaScript no momento da redação deste texto e quais diretivas de configuração fornecem esse acesso.
| Fase de processamento | Módulo HTTP | Módulo Stream |
|---|---|---|
Acesso – Autenticação e controle de acesso | auth_request e js_content | js_access |
Pré-leitura – Leitura/gravação da carga útil | N/D | js_preread |
Filtro – Leitura/gravação da resposta durante o proxy | js_body_filterjs_header_filter | js_filter |
Conteúdo – Envio da resposta ao cliente | js_content | N/D |
Log / Variáveis – Avaliação sob demanda | js_set | js_set |
Introdução ao NGINX JavaScript – Um exemplo do mundo real
O NGINX JavaScript é implementado como um módulo que você pode compilar em um binário do NGINX Open Source ou carregar dinamicamente no NGINX ou NGINX Plus. Instruções para habilitar o NGINX JavaScript com o NGINX e o NGINX Plus estão disponíveis no final deste artigo.
Neste exemplo, usamos o NGINX ou o NGINX Plus como um proxy reverso simples e o NGINX JavaScript para criar entradas de log de acesso em um formato especializado que:
- Inclui os cabeçalhos da solicitação enviados pelo cliente
- Inclui os cabeçalhos de resposta retornados pelo backend
- Usa pares de chave-valor para permitir a ingestão e a pesquisa eficientes em ferramentas de processamento de logs, como ELK Stack (agora chamada Elastic Stack), Graylog e Splunk
A configuração do NGINX para este exemplo é extremamente simples.
Carregando exemplo de código…
Como você pode ver, o código JavaScript do NGINX não fica inserido diretamente na sintaxe de configuração. Em vez disso, usamos a diretiva js_import para especificar o arquivo que contém todo o nosso código JavaScript. A diretiva js_set define uma nova variável do NGINX, $access_log_headers, e a função JavaScript que a preenche. A diretiva log_format define um novo formato chamado kvpairs, que grava cada linha do log com o valor de $access_log_headers.
O bloco server define um proxy reverso HTTP simples que encaminha todas as solicitações para https://www.example.com. A diretiva access_log especifica que todas as solicitações serão registradas no formato kvpairs.
Agora, vamos analisar o código JavaScript que prepara uma entrada de log.
Carregando exemplo de código…
O valor retornado pela função kvAccess — uma entrada de log — é passado para a diretiva de configuração js_set em rawheader_logging.conf. Lembre-se de que as variáveis do NGINX são avaliadas sob demanda, o que significa que a função JavaScript definida por js_set é executada quando o valor da variável é necessário. Neste exemplo, $access_log_headers é usada na diretiva log_format e, portanto, kvAccess() é executada no momento do registro. As variáveis usadas como parte das diretivas map ou rewrite (não ilustradas neste exemplo) acionam a execução do JavaScript correspondente em uma fase anterior do processamento.
Podemos ver essa solução de registro do NGINX aprimorada com JavaScript em ação ao encaminhar uma solicitação por meio do nosso proxy reverso e observar a entrada resultante no arquivo de log, que inclui cabeçalhos de solicitação com o prefixo in. e cabeçalhos de resposta com o prefixo 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=bytesGrande parte da utilidade do NGINX JavaScript resulta de seu acesso aos componentes internos do NGINX. Este exemplo utiliza várias propriedades do objeto de solicitação (r). O módulo Stream do NGINX JavaScript (para aplicações TCP e UDP) utiliza um objeto de sessão (s) com seu próprio conjunto de propriedades. Para ver outros exemplos de soluções do NGINX JavaScript para HTTP e TCP/UDP, consulte Casos de uso do módulo NGINX JavaScript.
Adoraríamos conhecer os casos de uso que você criar para o NGINX JavaScript. Conte-nos sobre eles na seção de comentários abaixo.
Casos de uso do módulo JavaScript do NGINX
Confira estas publicações do blog para conhecer outros casos de uso de HTTP e TCP/UDP para o módulo JavaScript do NGINX:
- Declaração de código JavaScript e variáveis em contextos locais em “Torne sua configuração do NGINX ainda mais modular e reutilizável com o njs 0.7.7”
- Como usar o NGINX como gateway DoT ou DoH
- Anunciando o NGINX Plus R26 – Uso de funções assíncronas; uso da API WebCrypto para gerar números aleatórios seguros e calcular o hash de strings de texto
- Mitigando a vulnerabilidade do log4j com o NGINX
- Registro avançado em log com o módulo JavaScript do NGINX em “Como escalar o MySQL com balanceamento de carga TCP e o Galera Cluster”
- Anunciando o NGINX Plus R24 – Filtragem de respostas tanto no corpo quanto nos cabeçalhos; uso do cliente HTTP incorporado para autenticar conexões TCP/UDP
- Validação de corpos de requisição em “Implantação do NGINX Plus como gateway de API, parte 2: proteção dos serviços de backend”
- Registro de diagnóstico com o módulo JavaScript do NGINX<.htmla>
- Anúncio do NGINX Plus R22 – Registro do conjunto exato de cabeçalhos enviados pelo cliente sempre que ocorre um erro
- Anunciando o NGINX Plus R21 – Encadeamento de subsolicitações em uma única sequência de código sem usar callbacks; envio de uma cópia dos cabeçalhos da solicitação para um sistema de gerenciamento de eventos e informações de segurança (SIEM)
- Apenas um POST: habilitando o DNS declarativo com a F5 e o módulo JavaScript do NGINX
- Estendendo o
auth_requestcom o módulo JavaScript do NGINX em “Validação de tokens de acesso OAuth 2.0 com NGINX e NGINX Plus” - Atualizações remotas de dispositivos IoT com o NGINX
- Anúncio do NGINX Plus R18 – Registro de uma versão com hash (mascarada) do endereço IP do cliente em vez do endereço real
- Aplicação de patches virtuais com o módulo JavaScript do NGINX
- Agrupamento de solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
- Anunciando o NGINX Plus R15 – Envio simultâneo de uma solicitação HTTP para dois back-ends diferentes, encaminhando a primeira resposta e ignorando a segunda; adição de integridade de dados aos cookies da aplicação
- Como escalar a detecção de alterações com hashing em JavaScript em “Como detectar adulterações na página inicial com verificações ativas de integridade”
- Ampliando o balanceamento de carga TCP.htmlUDP com nginScript em “Balanceamento de carga TCP/UDP com NGINX: visão geral, dicas e truques”
- Como usar certificados de cliente para autenticar clientes MQTT em “NGINX Plus para IoT: criptografia e autenticação do tráfego MQTT”
- Balanceamento de carga MQTT para persistência de sessão com o módulo JavaScript do NGINX em “NGINX Plus para IoT: balanceamento de carga MQTT”
- Mascaramento de dados para a privacidade do usuário com o módulo JavaScript do NGINX
- Anunciando o NGINX Plus R11 – Busca por padrões de chave em uma mensagem em um fluxo do protocolo MySQL para identificar a operação SQL
- Como usar o módulo JavaScript do NGINX para migrar clientes gradualmente para um novo servidor
[ngx_snippet name=’njs-enable-instructions’]
Sobre o autor

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.
Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.
Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.