Aproveitando o poder e a praticidade do JavaScript em cada requisição com o módulo JavaScript do NGINX

NGINX | 23 de abril de 2021

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:

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 processamentoMódulo HTTPMódulo Stream
Acesso – Autenticação e controle de acessoauth_request e js_contentjs_access
Pré-leitura – Leitura/gravação da carga útilN/Djs_preread
Filtro – Leitura/gravação da resposta durante o proxyjs_body_filter
js_header_filter
js_filter
Conteúdo – Envio da resposta ao clientejs_contentN/D
Log / Variáveis – Avaliação sob demandajs_setjs_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=bytes

Grande 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:

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


Compartilhar

Sobre o autor

Liam Crilly
Liam CrillyDiretor Sênior de Gestão de Produtos

Mais publicações de Liam Crilly

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

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
NGINX | 17/06/2024

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
NGINX | 14/07/2021

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
NGINX | 02/04/2019

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
NGINX | 24/05/2018

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
NGINX | 19/04/2016

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.