JS#

O módulo é usado para implementar manipuladores em njs — um subconjunto da linguagem JavaScript.

Em nossos repositórios, o módulo é compilado dinamicamente e está disponível como um pacote separado chamado angie-module-njs ou angie-pro-module-njs.

Nota

Uma versão leve do pacote, chamada ...-njs-light, também está disponível; no entanto, ela não pode ser usada junto com a versão regular.

Exemplo de Configuração#

stream {
    js_import stream.js;

    js_set $bar stream.bar;
    js_set $req_line stream.req_line;

    server {
        listen 12345;

        js_preread stream.preread;
        return     $req_line;
    }

    server {
        listen 12346;

        js_access  stream.access;
        proxy_pass 127.0.0.1:8000;
        js_filter  stream.header_inject;
    }
}

http {
    server {
        listen 8000;
        location / {
            return 200 $http_foo\n;
        }
    }
}

O arquivo stream.js:

var line = '';

function bar(s) {
    var v = s.variables;
    s.log("hello from bar() handler!");
    return "bar-var" + v.remote_port + "; pid=" + v.pid;
}

function preread(s) {
    s.on('upload', function (data, flags) {
        var n = data.indexOf('\n');
        if (n != -1) {
            line = data.substr(0, n);
            s.done();
        }
    });
}

function req_line(s) {
    return line;
}

// Read HTTP request line.
// Collect bytes in 'req' until
// request line is read.
// Inject HTTP header into a client's request

var my_header =  'Foo: foo';
function header_inject(s) {
    var req = '';
    s.on('upload', function(data, flags) {
        req += data;
        var n = req.search('\n');
        if (n != -1) {
            var rest = req.substr(n + 1);
            req = req.substr(0, n + 1);
            s.send(req + my_header + '\r\n' + rest, flags);
            s.off('upload');
        }
    });
}

function access(s) {
    if (s.remoteAddress.match('^192.*')) {
        s.deny();
        return;
    }

    s.allow();
}

export default {bar, preread, req_line, header_inject, access};

Diretivas#

js_access#

Sintaxe

js_access function | module.function;

Padrão

Contexto

stream, server

Define uma função njs que será chamada na fase de acesso. Funções de módulo podem ser referenciadas.

A função é chamada uma vez no momento em que a sessão de stream atinge a fase de acesso pela primeira vez. A função é chamada com os seguintes argumentos:

Nesta fase, é possível realizar inicialização ou registrar um callback com o método s.on() para cada bloco de dados recebido até que um dos seguintes métodos seja chamado: s.done(), s.decline(), s.allow(). Assim que um desses métodos é chamado, o processamento da sessão de stream muda para a próxima fase e todos os callbacks s.on() atuais são descartados.

js_context_reuse#

Sintaxe

js_context_reuse number;

Padrão

js_context_reuse 128;

Contexto

stream, server

Define o número máximo de contextos JS a serem reutilizados para o mecanismo QuickJS. Cada contexto é usado para uma única sessão de stream. O contexto finalizado é colocado em um pool de contextos reutilizáveis. Se o pool estiver cheio, o contexto é destruído.

js_engine#

Sintaxe

js_engine njs | qjs;

Padrão

js_engine njs;

Contexto

stream, server

Define o mecanismo JavaScript a ser usado para scripts njs. O parâmetro njs define o mecanismo njs, também usado por padrão. O parâmetro qjs define o mecanismo QuickJS.

js_fetch_buffer_size#

Sintaxe

js_fetch_buffer_size size;

Padrão

js_fetch_buffer_size 16k;

Contexto

stream, server

Define o tamanho do buffer usado para leitura e escrita com Fetch API.

js_fetch_ciphers#

Sintaxe

js_fetch_ciphers ciphers;

Padrão

js_fetch_ciphers HIGH:!aNULL:!MD5;

Contexto

stream, server

Especifica as cifras habilitadas para conexões HTTPS com Fetch API. As cifras são especificadas no formato compreendido pela biblioteca OpenSSL.

A lista de cifras depende da versão do OpenSSL instalada. A lista completa pode ser visualizada usando o comando openssl ciphers.

js_fetch_max_response_buffer_size#

Sintaxe

js_fetch_max_response_buffer_size size;

Padrão

js_fetch_max_response_buffer_size 1m;

Contexto

stream, server

Define o tamanho máximo da resposta recebida com Fetch API.

js_fetch_protocols#

Sintaxe

js_fetch_protocols [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3];

Padrão

js_fetch_protocols TLSv1 TLSv1.1 TLSv1.2;

Contexto

stream, server

Habilita os protocolos especificados para conexões HTTPS com Fetch API.

js_fetch_timeout#

Sintaxe

js_fetch_timeout time;

Padrão

js_fetch_timeout 60s;

Contexto

stream, server

Define um timeout para leitura e escrita para Fetch API. O timeout é definido apenas entre duas operações sucessivas de leitura/escrita, não para toda a resposta. Se nenhum dado for transmitido dentro deste tempo, a conexão é fechada.

js_fetch_trusted_certificate#

Sintaxe

js_fetch_trusted_certificate file;

Padrão

Contexto

stream, server

Especifica um arquivo com certificados CA confiáveis no formato PEM usado para verificar o certificado HTTPS com Fetch API.

js_fetch_verify#

Sintaxe

js_fetch_verify on | off;

Padrão

js_fetch_verify on;

Contexto

stream, server

Habilita ou desabilita a verificação do certificado do servidor HTTPS com Fetch API.

js_fetch_verify_depth#

Sintaxe

js_fetch_verify_depth number;

Padrão

js_fetch_verify_depth 100;

Contexto

stream, server

Define a profundidade de verificação na cadeia de certificados HTTPS com Fetch API.

js_fetch_keepalive#

Sintaxe

js_fetch_keepalive connections;

Padrão

js_fetch_keepalive 0;

Contexto

stream, server

Ativa o cache para conexões com servidores de destino. Quando o valor é maior que 0, habilita conexões keepalive para Fetch API.

O parâmetro connections define o número máximo de conexões keepalive ociosas para servidores de destino que são preservadas no cache de cada processo worker. Quando esse número é excedido, as conexões usadas menos recentemente são fechadas.

Exemplo:

server {
    listen 12345;
    js_fetch_keepalive 32;
    js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
    js_preread main.fetch_handler;
}

js_fetch_keepalive_requests#

Sintaxe

js_fetch_keepalive_requests number;

Padrão

js_fetch_keepalive_requests 1000;

Contexto

stream, server

Define o número máximo de requisições que podem ser atendidas através de uma conexão keepalive com Fetch API. Após o número máximo de requisições ser feito, a conexão é fechada.

Fechar conexões periodicamente é necessário para liberar alocações de memória por conexão. Portanto, usar um número máximo de requisições muito alto pode resultar em uso excessivo de memória e não é recomendado.

js_fetch_keepalive_time#

Sintaxe

js_fetch_keepalive_time time;

Padrão

js_fetch_keepalive_time 1h;

Contexto

stream, server

Limita o tempo máximo durante o qual as requisições podem ser processadas através de uma conexão keepalive com Fetch API. Após esse tempo ser atingido, a conexão é fechada após o processamento da requisição subsequente.

js_fetch_keepalive_timeout#

Sintaxe

js_fetch_keepalive_timeout time;

Padrão

js_fetch_keepalive_timeout 60s;

Contexto

stream, server

Define um timeout durante o qual uma conexão keepalive ociosa para um servidor de destino permanecerá aberta com Fetch API.

js_filter#

Sintaxe

js_filter function | module.function;

Padrão

Contexto

stream, server

Define um filtro de dados. Funções de módulo podem ser referenciadas.

A função de filtro é chamada uma vez no momento em que a sessão de stream atinge a fase de conteúdo. A função de filtro é chamada com os seguintes argumentos:

s

o objeto stream session

Nesta fase, é possível realizar inicialização ou registrar um callback com o método s.on() para cada bloco de dados recebido. O método s.off() pode ser usado para cancelar o registro de um callback e parar a filtragem.

Nota

Como o manipulador js_filter retorna seu resultado imediatamente, ele suporta apenas operações síncronas. Assim, operações assíncronas como ngx.fetch() ou setTimeout() não são suportadas.

js_import#

Sintaxe

js_import module.js | export_name from module.js;

Padrão

Contexto

stream, server

Importa um módulo que implementa manipuladores de localização e variável em njs. O export_name é usado como um namespace para acessar as funções do módulo. Se o export_name não for especificado, o nome do módulo será usado como namespace.

js_import stream.js;

Aqui, o nome do módulo stream é usado como namespace ao acessar as exportações. Se o módulo importado exporta foo(), então stream.foo é usado para acessá-la.

Várias diretivas js_import podem ser especificadas.

js_path#

Sintaxe

js_path path;

Padrão

Contexto

stream, server

Define um caminho adicional para módulos njs.

js_periodic#

Sintaxe

js_periodic module.function [interval=\ time] [jitter=\ number] [worker_affinity=\ mask];

Padrão

Contexto

server

Especifica um manipulador de conteúdo a ser executado em intervalos regulares. O manipulador recebe um objeto de sessão como seu primeiro argumento, e também tem acesso a objetos globais como ngx.

O parâmetro opcional interval define o intervalo entre duas execuções consecutivas, por padrão, 5 segundos.

O parâmetro opcional jitter define o tempo dentro do qual o manipulador de conteúdo da localização será atrasado aleatoriamente, por padrão, não há atraso.

Por padrão, o js_handler é executado no processo worker 0. O parâmetro opcional worker_affinity permite especificar processos worker particulares onde o manipulador de conteúdo da localização deve ser executado. Cada conjunto de processos worker é representado por uma máscara de bits de processos worker permitidos. A máscara all permite que o manipulador seja executado em todos os processos worker.

Exemplo:

example.conf:

location @periodics {
    # para ser executado em intervalos de 1 minuto no processo worker 0
    js_periodic main.handler interval=60s;

    # para ser executado em intervalos de 1 minuto em todos os processos worker
    js_periodic main.handler interval=60s worker_affinity=all;

    # para ser executado em intervalos de 1 minuto nos processos worker 1 e 3
    js_periodic main.handler interval=60s worker_affinity=0101;

    resolver 10.0.0.1;
    js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}
example.js:

async function handler(s) {
    let reply = await ngx.fetch('https://example.com/');
    let body = await reply.text();

    ngx.log(ngx.INFO, body);
}

js_preload_object#

Sintaxe

js_preload_object name.json | name from file.json;

Padrão

Contexto

stream, server

Pré-carrega um objeto imutável no momento da configuração. O name é usado como nome da variável global através da qual o objeto está disponível no código njs. Se o name não for especificado, o nome do arquivo será usado em seu lugar.

js_preload_object map.json;

Aqui, o map é usado como nome ao acessar o objeto pré-carregado.

Várias diretivas js_preload_object podem ser especificadas.

js_preread#

Sintaxe

js_preread function | module.function;

Padrão

Contexto

stream, server

Define uma função njs que será chamada na fase de pré-leitura. Funções de módulo podem ser referenciadas.

A função é chamada uma vez no momento em que a sessão de stream atinge a fase de pré-leitura pela primeira vez. A função é chamada com os seguintes argumentos:

s

o objeto stream session

Nesta fase, é possível realizar inicialização ou registrar um callback com o método s.on() para cada bloco de dados recebido até que um dos seguintes métodos seja chamado: s.done(), s.decline(), s.allow(). Quando um desses métodos é chamado, a sessão de stream muda para a próxima fase e todos os callbacks s.on() atuais são descartados.

Nota

Como o manipulador js_preread retorna seu resultado imediatamente, ele suporta apenas operações síncronas. Assim, operações assíncronas como ngx.fetch() ou setTimeout() não são suportadas. No entanto, operações assíncronas são suportadas em callbacks s.on() na fase de pré-leitura.

js_set#

Sintaxe

js_set $variable function | module.function [nocache];

Padrão

Contexto

stream, server

Define uma função njs para a variável especificada. Funções de módulo podem ser referenciadas.

A função é chamada quando a variável é referenciada pela primeira vez para uma determinada requisição. O momento exato depende de uma fase na qual a variável é referenciada. Isso pode ser usado para executar alguma lógica não relacionada à avaliação da variável. Por exemplo, se a variável é referenciada apenas na diretiva log_format, seu manipulador não será executado até a fase de log. Este manipulador pode ser usado para fazer alguma limpeza logo antes da requisição ser liberada.

Desde o njs 0.8.6, quando o argumento opcional nocache é fornecido, o manipulador é chamado toda vez que é referenciado. Devido às limitações atuais do módulo rewrite, quando uma variável nocache é referenciada pela diretiva set, seu manipulador deve sempre retornar um valor de comprimento fixo.

Nota

Como o manipulador js_set retorna seu resultado imediatamente, ele suporta apenas operações síncronas. Assim, operações assíncronas como ngx.fetch() ou setTimeout() não são suportadas.

js_shared_dict_zone#

Sintaxe

js_shared_dict_zone zone=name:size [timeout=time] [type=string | number] [evict] [state=file];

Padrão

Contexto

stream

Define o nome e tamanho da zona de memória compartilhada que mantém o dicionário chave-valor compartilhado entre os processos worker.

type

parâmetro opcional, permite redefinir o tipo de valor para number, por padrão o dicionário compartilhado usa uma string como chave e valor

timeout

parâmetro opcional, define o tempo após o qual todas as entradas do dicionário compartilhado são removidas da zona

evict

parâmetro opcional, remove o par chave-valor mais antigo quando o armazenamento da zona está esgotado

state

parâmetro opcional, especifica um arquivo que mantém o estado do dicionário compartilhado em formato JSON e o torna persistente entre reinicializações do nginx

Exemplos:

example.conf:
    # Cria um dicionário de 1Mb com valores string,
    # remove pares chave-valor após 60 segundos de inatividade:
    js_shared_dict_zone zone=foo:1M timeout=60s;

    # Cria um dicionário de 512Kb com valores string,
    # remove forçadamente os pares chave-valor mais antigos quando a zona está esgotada:
    js_shared_dict_zone zone=bar:512K timeout=30s evict;

    # Cria um dicionário permanente de 32Kb com valores numéricos:
    js_shared_dict_zone zone=num:32k type=number;

    # Cria um dicionário de 1Mb com valores string e estado persistente:
    js_shared_dict_zone zone=persistent:1M state=/tmp/dict.json;
example.js:
    function get(r) {
        r.return(200, ngx.shared.foo.get(r.args.key));
    }

    function set(r) {
        r.return(200, ngx.shared.foo.set(r.args.key, r.args.value));
    }

    function delete(r) {
        r.return(200, ngx.shared.bar.delete(r.args.key));
    }

    function increment(r) {
        r.return(200, ngx.shared.num.incr(r.args.key, 2));
    }

js_var#

Sintaxe

js_var $variável [valor];

Padrão

Contexto

stream, server

Declara uma variável gravável. O valor pode conter texto, variáveis e sua combinação.

Propriedades do Objeto de Sessão#

Cada manipulador njs de stream recebe um argumento, um objeto stream session.