echo: módulo Echo do nginx
Instalação
Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:
- RedHat Enterprise Linux 7, 8, 9 e 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 e Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-echo
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-echo
Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:
load_module modules/ngx_http_echo_module.so;
Este documento descreve o nginx-module-echo v0.64 lançado em 30 de outubro de 2025.
location /hello {
echo "hello, world!";
}
location /hello {
echo -n "hello, ";
echo "world!";
}
location /timed_hello {
echo_reset_timer;
echo hello world;
echo "'hello world' takes about $echo_timer_elapsed sec.";
echo hiya igor;
echo "'hiya igor' takes about $echo_timer_elapsed sec.";
}
location /echo_with_sleep {
echo hello;
echo_flush; # ensure the client can see previous output immediately
echo_sleep 2.5; # in sec
echo world;
}
# no exemplo a seguir, acessar /echo resulta em
# hello
# world
# blah
# hiya
# igor
location /echo {
echo_before_body hello;
echo_before_body world;
proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more;
echo_after_body hiya;
echo_after_body igor;
}
location /echo/more {
echo blah;
}
# a saída de /main pode ser
# hello
# world
# took 0.000 sec for total.
# e toda a requisição levaria cerca de 2 sec para completar.
location /main {
echo_reset_timer;
# subrequisições em paralelo
echo_location_async /sub1;
echo_location_async /sub2;
echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
echo_sleep 2;
echo hello;
}
location /sub2 {
echo_sleep 1;
echo world;
}
# a saída de /main pode ser
# hello
# world
# took 3.003 sec for total.
# e toda a requisição levaria cerca de 3 sec para completar.
location /main {
echo_reset_timer;
# subrequisições em série (encadeadas por CPS)
echo_location /sub1;
echo_location /sub2;
echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
echo_sleep 2;
echo hello;
}
location /sub2 {
echo_sleep 1;
echo world;
}
# Acessar /dup resulta em
# ------ END ------
location /dup {
echo_duplicate 3 "--";
echo_duplicate 1 " END ";
echo_duplicate 3 "--";
echo;
}
# /bighello gerará 1000.000.000 hello's.
location /bighello {
echo_duplicate 1000_000_000 'hello';
}
# ecoa de volta a requisição do cliente
location /echoback {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo_read_request_body;
echo_request_body;
}
# GET /multi resultará em
# querystring: foo=Foo
# method: POST
# body: hi
# content length: 2
# ///
# querystring: bar=Bar
# method: PUT
# body: hello
# content length: 5
# ///
location /multi {
echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi';
echo_subrequest_async PUT '/sub' -q 'bar=Bar' -b 'hello';
}
location /sub {
echo "querystring: $query_string";
echo "method: $echo_request_method";
echo "body: $echo_request_body";
echo "content length: $http_content_length";
echo '///';
}
# GET /merge?/foo.js&/bar/blah.js&/yui/baz.js irá mesclar os recursos .js juntos
location /merge {
default_type 'text/javascript';
echo_foreach_split '&' $query_string;
echo "/* JS File $echo_it */";
echo_location_async $echo_it;
echo;
echo_end;
}
# acessar /if?val=abc resulta na saída "hit"
# enquanto /if?val=bcd resulta em "miss":
location ^~ /if {
set $res miss;
if ($arg_val ~* '^a') {
set $res hit;
echo $res;
}
echo $res;
}
Descrição
Este módulo envolve muitas APIs internas do Nginx para streaming de entrada e saída, subrequisições paralelas/sequenciais, temporizadores e sono, bem como acesso a vários metadados.
Basicamente, ele fornece várias utilidades que ajudam a testar e depurar outros módulos, emulando trivialmente diferentes tipos de locais de subrequisições falsificadas.
As pessoas também acharão útil em aplicações do mundo real que precisam
- servir conteúdos estáticos diretamente da memória (carregando do arquivo de configuração do Nginx).
- envolver a resposta upstream com cabeçalho e rodapé personalizados (meio que como o módulo de adição, mas com conteúdos lidos diretamente do arquivo de configuração e variáveis do Nginx).
- mesclar conteúdos de vários "locais do Nginx" (ou seja, subrequisições) juntos em uma única requisição principal (usando echo_location e seus amigos).
Este é um módulo de dupla função especial que pode lazily servir como um manipulador de conteúdo ou registrar-se como um filtro de saída apenas sob demanda. Por padrão, este módulo não faz nada.
Tecnicamente, este módulo também demonstrou as seguintes técnicas que podem ser úteis para escritores de módulos:
- Emitir subrequisições paralelas diretamente do manipulador de conteúdo.
- Emitir subrequisições encadeadas diretamente do manipulador de conteúdo, passando a continuação ao longo da cadeia de subrequisições.
- Emitir subrequisições com todos os métodos HTTP 1.1 e até um corpo de requisição HTTP falsificado opcional.
- Interagir com o modelo de eventos do Nginx diretamente do manipulador de conteúdo usando eventos e temporizadores personalizados, e retomar o manipulador de conteúdo de volta se necessário.
- Módulo de dupla função que pode (lazily) servir como um manipulador de conteúdo ou um filtro de saída ou ambos.
- Criação e interpolação de variáveis do arquivo de configuração do Nginx.
- Controle de saída de streaming usando output_chain, flush e seus amigos.
- Ler o corpo da requisição do cliente a partir do manipulador de conteúdo e retornar (assíncronamente) ao manipulador de conteúdo após a conclusão.
- Usar um conjunto de testes declarativos baseado em Perl test suite para conduzir o desenvolvimento de módulos C do Nginx.
Diretivas do Manipulador de Conteúdo
O uso das seguintes diretivas registra este módulo no local atual do Nginx como um manipulador de conteúdo. Se você quiser usar outro módulo, como o módulo proxy padrão, como o manipulador de conteúdo, use as diretivas de filtro fornecidas por este módulo.
Todas as diretivas do manipulador de conteúdo podem ser misturadas em uma única configuração de local do Nginx e devem ser executadas sequencialmente, assim como na linguagem de script Bash.
Cada diretiva do manipulador de conteúdo suporta interpolação de variáveis em seus argumentos (se houver).
O tipo MIME definido pela diretiva default_type padrão é respeitado por este módulo, como em:
location /hello {
default_type text/plain;
echo hello;
}
Então, do lado do cliente:
$ curl -I 'http://localhost/echo'
HTTP/1.1 200 OK
Server: nginx/0.8.20
Date: Sat, 17 Oct 2009 03:40:19 GMT
Content-Type: text/plain
Connection: keep-alive
Desde o lançamento v0.22, todas as diretivas são permitidas no bloco da diretiva if do módulo rewrite, por exemplo:
location ^~ /if {
set $res miss;
if ($arg_val ~* '^a') {
set $res hit;
echo $res;
}
echo $res;
}
echo
sintaxe: echo [options] <string>...
padrão: não
contexto: location, location if
fase: content
Envia argumentos unidos por espaços, juntamente com uma nova linha final, para o cliente.
Observe que os dados podem ser armazenados em buffer pelo buffer subjacente do Nginx. Para forçar que os dados de saída sejam enviados imediatamente, use o comando echo_flush logo após echo, como em
echo hello world;
echo_flush;
Quando nenhum argumento é especificado, echo emite apenas a nova linha final, assim como o comando echo no shell.
Variáveis podem aparecer nos argumentos. Um exemplo é
echo The current request uri is $request_uri;
onde $request_uri é uma variável exposta pelo ngx_http_core_module.
Este comando pode ser usado várias vezes em uma única configuração de local, como em
location /echo {
echo hello;
echo world;
}
A saída do lado do cliente fica assim
$ curl 'http://localhost/echo'
hello
world
Caracteres especiais como novas linhas (\n) e tabulações (\t) podem ser escapados usando sequências de escape no estilo C. Mas uma exceção notável é o sinal de dólar ($). A partir do Nginx 0.8.20, ainda não há uma maneira limpa de escapar esse caractere. (Uma solução alternativa pode ser usar uma variável $echo_dollor que é sempre avaliada para o caractere constante $. Esse recurso será possivelmente introduzido em uma versão futura deste módulo.)
A partir do lançamento do echo v0.28, pode-se suprimir o caractere de nova linha final na saída usando a opção -n, como em
location /echo {
echo -n "hello, ";
echo "world";
}
Acessar /echo resulta em
$ curl 'http://localhost/echo'
hello, world
Um -n inicial em valores de variáveis não terá efeito e será emitido literalmente, como em
location /echo {
set $opt -n;
echo $opt "hello,";
echo "world";
}
Isso dá a seguinte saída
$ curl 'http://localhost/echo'
-n hello,
world
Pode-se outputar literais -n iniciais e outras opções usando a opção especial -- assim
location /echo {
echo -- -n is an option;
}
o que resulta em
$ curl 'http://localhost/echo'
-n is an option
Use esta forma quando você quiser outputar qualquer coisa que comece com um hífen (-).
echo_duplicate
sintaxe: echo_duplicate <count> <string>
padrão: não
contexto: location, location if
fase: content
Emite a duplicação de uma string indicada pelo segundo argumento, usando a contagem especificada no primeiro argumento.
Por exemplo,
location /dup {
echo_duplicate 3 "abc";
}
resultará na saída de "abcabcabc".
Sublinhados são permitidos no número da contagem, assim como em Perl. Por exemplo, para emitir 1000.000.000 instâncias de "hello, world":
location /many_hellos {
echo_duplicate 1000_000_000 "hello, world";
}
O argumento count poderia ser zero, mas não negativo. O segundo argumento string poderia ser uma string vazia ("") também.
Diferente da diretiva echo, nenhuma nova linha final é anexada ao resultado. Portanto, é possível "abusar" desta diretiva como uma versão sem nova linha final da echo usando "count" 1, como em
location /echo_art {
echo_duplicate 2 '---';
echo_duplicate 1 ' END '; # não queremos uma nova linha final aqui
echo_duplicate 2 '---';
echo; # queremos uma nova linha final aqui...
}
Você obtém
------ END ------
Mas o uso da opção -n na echo é mais apropriado para esse propósito.
Esta diretiva foi introduzida pela primeira vez na versão 0.11.
echo_flush
sintaxe: echo_flush
padrão: não
contexto: location, location if
fase: content
Força os dados potencialmente armazenados em buffer pelos filtros de saída subjacentes do Nginx a serem enviados imediatamente para o lado do cliente via socket.
Observe que tecnicamente o comando apenas emite um objeto ngx_buf_t com o slot flush definido como 1, então certos módulos de filtro de saída de terceiros estranhos ainda podem bloqueá-lo antes que ele chegue ao filtro de escrita (último) do Nginx.
Esta diretiva não aceita nenhum argumento.
Considere o seguinte exemplo:
location /flush {
echo hello;
echo_flush;
echo_sleep 1;
echo world;
}
Então, do lado do cliente, usando curl para acessar /flush, você verá a linha "hello" imediatamente, mas apenas após 1 segundo, a última linha "world". Sem chamar echo_flush no exemplo acima, você provavelmente não verá nenhuma saída até que 1 segundo tenha se passado devido ao buffering interno do Nginx.
Esta diretiva falhará em limpar o buffer de saída caso subrequisições estejam envolvidas. Considere o seguinte exemplo:
location /main {
echo_location_async /sub;
echo hello;
echo_flush;
}
location /sub {
echo_sleep 1;
}
Então o cliente não verá "hello" aparecer mesmo que echo_flush tenha sido executado antes que a subrequisição para /sub tenha realmente começado a ser executada. As saídas de /main que são enviadas após echo_location_async serão adiadas e armazenadas em buffer firmemente.
Isso não se aplica a saídas enviadas antes da subrequisição ser iniciada. Para uma versão modificada do exemplo dado acima:
location /main {
echo hello;
echo_flush;
echo_location_async /sub;
}
location /sub {
echo_sleep 1;
}
O cliente verá imediatamente "hello" antes que /sub entre em sono.
Veja também echo, echo_sleep e echo_location_async.
echo_sleep
sintaxe: echo_sleep <seconds>
padrão: não
contexto: location, location if
fase: content
Dorme pelo período de tempo especificado pelo argumento, que está em segundos.
Esta operação é não bloqueante no lado do servidor, então, ao contrário da diretiva echo_blocking_sleep, não bloqueará todo o processo de trabalho do Nginx.
O período pode ter três dígitos após o ponto decimal e deve ser maior que 0.001.
Um exemplo é
location /echo_after_sleep {
echo_sleep 1.234;
echo resumed!;
}
Nos bastidores, ele configura um objeto "sleep" ngx_event_t por requisição e adiciona um temporizador usando esse evento personalizado ao modelo de eventos do Nginx e apenas espera por um timeout nesse evento. Como o evento "sleep" é por requisição, esta diretiva pode funcionar em subrequisições paralelas.
echo_blocking_sleep
sintaxe: echo_blocking_sleep <seconds>
padrão: não
contexto: location, location if
fase: content
Esta é uma versão bloqueante da diretiva echo_sleep.
Veja a documentação da echo_sleep para mais detalhes.
Nos bastidores, ela chama a macro ngx_msleep fornecida pelo núcleo do Nginx, que mapeia para usleep em sistemas compatíveis com POSIX.
Observe que esta diretiva bloqueará completamente o processo de trabalho atual do Nginx enquanto estiver sendo executada, então nunca a use em ambiente de produção.
echo_reset_timer
sintaxe: echo_reset_timer
padrão: não
contexto: location, location if
fase: content
Redefine o tempo de início do temporizador para agora, ou seja, o tempo em que este comando é executado durante a requisição.
O tempo de início do temporizador é padrão para o tempo de início da requisição atual e pode ser substituído por esta diretiva, potencialmente várias vezes em um único local. Por exemplo:
location /timed_sleep {
echo_sleep 0.03;
echo "$echo_timer_elapsed sec elapsed.";
echo_reset_timer;
echo_sleep 0.02;
echo "$echo_timer_elapsed sec elapsed.";
}
A saída do lado do cliente pode ser
$ curl 'http://localhost/timed_sleep'
0.032 sec elapsed.
0.020 sec elapsed.
Os números reais que você obtém do seu lado podem variar um pouco devido às atividades atuais do seu sistema.
A invocação desta diretiva forçará o temporizador subjacente do Nginx a ser atualizado para o tempo do sistema atual (independentemente da resolução do temporizador especificada em outro lugar no arquivo de configuração). Além disso, referências da variável $echo_timer_elapsed também forçarão a atualização do temporizador.
Veja também echo_sleep e $echo_timer_elapsed.
echo_read_request_body
sintaxe: echo_read_request_body
padrão: não
contexto: location, location if
fase: content
Lê explicitamente o corpo da requisição para que a variável $request_body sempre tenha valores não vazios (a menos que o corpo seja tão grande que tenha sido salvo pelo Nginx em um arquivo temporário local).
Observe que isso pode não ser o corpo original da requisição do cliente porque a requisição atual pode ser uma subrequisição com um corpo "artificial" especificado por seu pai.
Esta diretiva não gera nenhuma saída por si só, assim como echo_sleep.
Aqui está um exemplo para ecoar de volta a requisição HTTP original do cliente (tanto os cabeçalhos quanto o corpo estão incluídos):
location /echoback {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo_read_request_body;
echo $request_body;
}
O conteúdo de /echoback parece assim do meu lado (eu estava usando a utilidade LWP do Perl para acessar este local no servidor):
$ (echo hello; echo world) | lwp-request -m POST 'http://localhost/echoback'
POST /echoback HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: lwp-request/5.818 libwww-perl/5.820
Content-Length: 12
Content-Type: application/x-www-form-urlencoded
hello
world
Porque /echoback é a requisição principal, $request_body contém o corpo original da requisição do cliente.
Antes do Nginx 0.7.56, não fazia sentido usar esta diretiva porque $request_body foi introduzido pela primeira vez no Nginx 0.7.58.
Esta diretiva foi introduzida pela primeira vez na v0.14 release do módulo echo.
echo_location_async
sintaxe: echo_location_async <location> [<url_args>]
padrão: não
contexto: location, location if
fase: content
Emite uma subrequisição GET para o local especificado (primeiro argumento) com argumentos de URL opcionais especificados no segundo argumento.
A partir do Nginx 0.8.20, o argumento location não suporta locais nomeados, devido a uma limitação na função ngx_http_subrequest. O mesmo é verdadeiro para seu irmão, a diretiva echo_location.
Um exemplo muito simples é
location /main {
echo_location_async /sub;
echo world;
}
location /sub {
echo hello;
}
Acessar /main resulta em
hello
world
Chamar vários locais em paralelo também é possível:
location /main {
echo_reset_timer;
echo_location_async /sub1;
echo_location_async /sub2;
echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
echo_sleep 2; # dorme 2 sec
echo hello;
}
location /sub2 {
echo_sleep 1; # dorme 1 sec
echo world;
}
Acessar /main resulta em
$ time curl 'http://localhost/main'
hello
world
took 0.000 sec for total.
real 0m2.006s
user 0m0.000s
sys 0m0.004s
Você pode ver que o manipulador principal /main não espera que as subrequisições /sub1 e /sub2 sejam concluídas e rapidamente continua, daí o resultado de tempo "0.000 sec". A requisição inteira, no entanto, leva aproximadamente 2 sec no total para completar porque /sub1 e /sub2 são executadas em paralelo (ou "concorrentemente" para ser mais preciso).
Se você usar echo_blocking_sleep no exemplo anterior, então você obterá a mesma saída, mas com 3 sec de tempo total de resposta, porque "bloquear o sono" bloqueia todo o processo de trabalho do Nginx.
Os locais também podem aceitar um argumento de querystring opcional, por exemplo
location /main {
echo_location_async /sub 'foo=Foo&bar=Bar';
}
location /sub {
echo $arg_foo $arg_bar;
}
Acessar /main resulta em
$ curl 'http://localhost/main'
Foo Bar
Querystrings não podem ser concatenadas ao argumento location com "?" diretamente, por exemplo, /sub?foo=Foo&bar=Bar é um local inválido e não deve ser fornecido como o primeiro argumento para esta diretiva.
Tecnicamente falando, esta diretiva é um exemplo de como o manipulador de conteúdo do Nginx emite uma ou mais subrequisições diretamente. Até onde sei, o módulo fancyindex também faz esse tipo de coisa ;)
Locais nomeados do Nginx como @foo não são suportados aqui.
Esta diretiva é logicamente equivalente à versão GET de echo_subrequest_async. Por exemplo,
echo_location_async /foo 'bar=Bar';
é logicamente equivalente a
echo_subrequest_async GET /foo -q 'bar=Bar';
Mas chamar esta diretiva é ligeiramente mais rápido do que chamar echo_subrequest_async usando GET porque não precisamos analisar os nomes dos métodos HTTP como GET e opções como -q.
Esta diretiva foi introduzida pela primeira vez na versão 0.09 deste módulo e requer pelo menos Nginx 0.7.46.
echo_location
sintaxe: echo_location <location> [<url_args>]
padrão: não
contexto: location, location if
fase: content
Assim como a diretiva echo_location_async, mas echo_location emite subrequisições em série em vez de em paralelo. Ou seja, as diretivas do manipulador de conteúdo que seguem esta diretiva não serão executadas até que a subrequisição emitida por esta diretiva seja concluída.
O corpo da resposta final é quase sempre equivalente ao caso em que echo_location_async é usado em vez disso, apenas se variáveis de tempo forem usadas nas saídas.
Considere o seguinte exemplo:
location /main {
echo_reset_timer;
echo_location /sub1;
echo_location /sub2;
echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
echo_sleep 2;
echo hello;
}
location /sub2 {
echo_sleep 1;
echo world;
}
O local /main acima levará um total de 3 sec para completar (comparado a 2 sec se echo_location_async for usado em vez disso). Aqui está o resultado em ação na minha máquina:
$ curl 'http://localhost/main'
hello
world
took 3.003 sec for total.
real 0m3.027s
user 0m0.020s
sys 0m0.004s
Esta diretiva é logicamente equivalente à versão GET de echo_subrequest. Por exemplo,
echo_location /foo 'bar=Bar';
é logicamente equivalente a
echo_subrequest GET /foo -q 'bar=Bar';
Mas chamar esta diretiva é ligeiramente mais rápido do que chamar echo_subrequest usando GET porque não precisamos analisar os nomes dos métodos HTTP como GET e opções como -q.
Nos bastidores, ela cria um objeto ngx_http_post_subrequest_t como uma continuação e o passa para a chamada da função ngx_http_subrequest. O Nginx mais tarde reabre esta "continuação" na chamada da função ngx_http_finalize_request da subrequisição. Retomamos a execução do manipulador de conteúdo da requisição pai e começamos a executar a próxima diretiva (comando) se houver.
Locais nomeados do Nginx como @foo não são suportados aqui.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.12.
Veja também echo_location_async para mais detalhes sobre o significado dos argumentos.
echo_subrequest_async
sintaxe: echo_subrequest_async <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]
padrão: não
contexto: location, location if
fase: content
Inicia uma subrequisição assíncrona usando o método HTTP, um argumento de URL opcional (ou querystring) e um corpo de requisição opcional que pode ser definido como uma string ou como um caminho para um arquivo que contém o corpo.
Esta diretiva é muito semelhante a uma versão generalizada da diretiva echo_location_async.
Aqui está um pequeno exemplo demonstrando seu uso:
location /multi {
# corpo definido como string
echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi';
# corpo definido como caminho para um arquivo, relativo ao caminho prefixo do nginx se não for absoluto
echo_subrequest_async PUT '/sub' -q 'bar=Bar' -f '/tmp/hello.txt';
}
location /sub {
echo "querystring: $query_string";
echo "method: $echo_request_method";
echo "body: $echo_request_body";
echo "content length: $http_content_length";
echo '///';
}
Então, do lado do cliente:
$ echo -n hello > /tmp/hello.txt
$ curl 'http://localhost/multi'
querystring: foo=Foo
method: POST
body: hi
content length: 2
///
querystring: bar=Bar
method: PUT
body: hello
content length: 5
///
Aqui está um exemplo mais engraçado usando o módulo padrão proxy para lidar com a subrequisição:
location /main {
echo_subrequest_async POST /sub -b 'hello, world';
}
location /sub {
proxy_pass $scheme://127.0.0.1:$server_port/proxied;
}
location /proxied {
echo "method: $echo_request_method.";
# precisamos ler o corpo explicitamente aqui...ou $echo_request_body
# será avaliado como vazio ("")
echo_read_request_body;
echo "body: $echo_request_body.";
}
Então, do lado do cliente, podemos ver que
$ curl 'http://localhost/main'
method: POST.
body: hello, world.
Locais nomeados do Nginx como @foo não são suportados aqui.
Esta diretiva aceita várias opções:
-q <url_args> Especifica os argumentos de URL (ou querystring) para a subrequisição.
-f <path> Especifica o caminho para o arquivo cujo conteúdo será usado como o
corpo da requisição da subrequisição.
-b <data> Especifica os dados do corpo da requisição.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.15.
A opção -f para definir um caminho de arquivo para o corpo foi introduzida no lançamento v0.35.
Veja também as diretivas echo_subrequest e echo_location_async.
echo_subrequest
sintaxe: echo_subrequest <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]
padrão: não
contexto: location, location if
fase: content
Esta é a versão síncrona da diretiva echo_subrequest_async. E assim como echo_location, não bloqueia o processo de trabalho do Nginx (enquanto echo_blocking_sleep faz), em vez disso, usa continuação para passar o controle ao longo da cadeia de subrequisições.
Veja echo_subrequest_async para mais detalhes.
Locais nomeados do Nginx como @foo não são suportados aqui.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.15.
echo_foreach_split
sintaxe: echo_foreach_split <delimiter> <string>
padrão: não
contexto: location, location if
fase: content
Divide o segundo argumento string usando o delimitador especificado no primeiro argumento e, em seguida, itera pelos itens resultantes. Por exemplo:
location /loop {
echo_foreach_split ',' $arg_list;
echo "item: $echo_it";
echo_end;
}
Acessar /main resulta em
$ curl 'http://localhost/loop?list=cat,dog,mouse'
item: cat
item: dog
item: mouse
Como visto no exemplo anterior, esta diretiva deve sempre ser acompanhada por uma diretiva echo_end.
Laços paralelos echo_foreach_split são permitidos, mas aninhados atualmente são proibidos.
O argumento delimiter pode conter múltiplos caracteres arbitrários, como
# isso produz "cat\ndog\nmouse\n"
echo_foreach_split -- '-a-' 'cat-a-dog-a-mouse';
echo $echo_it;
echo_end;
Logicamente falando, esta estrutura de laço é apenas o laço foreach combinado com uma chamada de função split em Perl (usando o exemplo anterior):
foreach (split ',', $arg_list) {
print "item $_\n";
}
As pessoas também acharão útil na mesclagem de vários recursos .js ou .css em um todo. Aqui está um exemplo:
location /merge {
default_type 'text/javascript';
echo_foreach_split '&' $query_string;
echo "/* JS File $echo_it */";
echo_location_async $echo_it;
echo;
echo_end;
}
Então, acessando /merge para mesclar os recursos .js especificados na query string:
$ curl 'http://localhost/merge?/foo/bar.js&/yui/blah.js&/baz.js'
Pode-se também usar um módulo de cache Nginx de terceiros para armazenar em cache a resposta mesclada gerada pela localização /merge no exemplo anterior.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.17.
echo_end
sintaxe: echo_end
padrão: não
contexto: location, location if
fase: content
Esta diretiva é usada para terminar o corpo de estruturas de controle de loop e condicionais como echo_foreach_split.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.17.
echo_request_body
sintaxe: echo_request_body
padrão: não
contexto: location, location if
fase: content
Emite o conteúdo do corpo da requisição lido anteriormente.
Nos bastidores, é implementado aproximadamente assim:
if (r->request_body && r->request_body->bufs) {
return ngx_http_output_filter(r, r->request_body->bufs);
}
Diferente das variáveis $echo_request_body e $request_body, esta diretiva mostrará todo o corpo da requisição mesmo que algumas partes ou todas as partes dele estejam salvas em arquivos temporários no disco.
É uma "no-op" se nenhum corpo de requisição tiver sido lido ainda.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.18.
Veja também echo_read_request_body e o módulo chunkin.
echo_exec
sintaxe: echo_exec <location> [<query_string>]
sintaxe: echo_exec <named_location>
padrão: não
contexto: location, location if
fase: content
Faz um redirecionamento interno para o local especificado. Uma query string opcional pode ser especificada para locais normais, como em
location /foo {
echo_exec /bar weight=5;
}
location /bar {
echo $arg_weight;
}
Ou equivalente
location /foo {
echo_exec /bar?weight=5;
}
location /bar {
echo $arg_weight;
}
Locais nomeados também são suportados. Aqui está um exemplo:
location /foo {
echo_exec @bar;
}
location @bar {
# você obterá /foo em vez de @bar
# devido a um bug potencial no nginx.
echo $echo_request_uri;
}
Mas a query string (se houver) sempre será ignorada para redirecionamentos de locais nomeados devido a uma limitação na função ngx_http_named_location.
Nunca tente ecoar coisas antes da diretiva echo_exec ou você não verá a resposta adequada do local para o qual deseja redirecionar. Porque qualquer ecoação fará com que o manipulador de local original envie cabeçalhos HTTP antes que o redirecionamento ocorra.
Tecnicamente falando, esta diretiva expõe as funções da API interna do Nginx ngx_http_internal_redirect e ngx_http_named_location.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.21.
echo_status
sintaxe: echo_status <status-num>
padrão: echo_status 200
contexto: location, location if
fase: content
Especifica o código de status de resposta padrão. Padrão para 200. Esta diretiva é declarativa e a ordem relativa com outras diretivas semelhantes ao echo não é importante.
Aqui está um exemplo,
location = /bad {
echo_status 404;
echo "Something is missing...";
}
então obtemos uma resposta assim:
HTTP/1.1 404 Not Found
Server: nginx/1.2.1
Date: Sun, 24 Jun 2012 03:58:18 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Something is missing...
Esta diretiva foi introduzida pela primeira vez no lançamento v0.40.
Diretivas de Filtro
O uso das seguintes diretivas aciona o registro de filtro deste módulo. Por padrão, nenhum filtro será registrado por este módulo.
Cada diretiva de filtro suporta interpolação de variáveis em seus argumentos (se houver).
echo_before_body
sintaxe: echo_before_body [options] [argument]...
padrão: não
contexto: location, location if
fase: output filter
É a versão de filtro da diretiva echo, e prepend sua saída ao início das saídas originais geradas pelo manipulador de conteúdo subjacente.
Um exemplo é
location /echo {
echo_before_body hello;
proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more;
}
location /echo/more {
echo world
}
Acessar /echo do lado do cliente resulta em
hello
world
No exemplo anterior, pegamos o módulo proxy padrão para servir como o manipulador de conteúdo subjacente que gera os "conteúdos principais".
Múltiplas instâncias desta diretiva de filtro também são permitidas, como em:
location /echo {
echo_before_body hello;
echo_before_body world;
echo !;
}
Do lado do cliente, a saída é assim
$ curl 'http://localhost/echo'
hello
world
!
Neste exemplo, também usamos as diretivas do manipulador de conteúdo fornecidas por este módulo como o manipulador de conteúdo subjacente.
Esta diretiva também suporta as opções -n e -- como a diretiva echo.
Esta diretiva pode ser misturada com sua diretiva irmã echo_after_body.
echo_after_body
sintaxe: echo_after_body [argument]...
padrão: não
contexto: location, location if
fase: output filter
É muito semelhante à diretiva echo_before_body, mas anexa sua saída ao final das saídas originais geradas pelo manipulador de conteúdo subjacente.
Aqui está um exemplo simples:
location /echo {
echo_after_body hello;
proxy_pass http://127.0.0.1:$server_port$request_uri/more;
}
location /echo/more {
echo world
}
Acessar /echo do lado do cliente resulta em
world
hello
Múltiplas instâncias são permitidas, como em:
location /echo {
echo_after_body hello;
echo_after_body world;
echo i;
echo say;
}
A saída do lado do cliente ao acessar a localização /echo parece assim
i
say
hello
world
Esta diretiva também suporta as opções -n e -- como a diretiva echo.
Esta diretiva pode ser misturada com sua diretiva irmã echo_before_body.
Variáveis
$echo_it
Esta é uma "variável de tópico" usada por echo_foreach_split, assim como a variável $_ em Perl.
$echo_timer_elapsed
Esta variável contém os segundos decorridos desde o início da requisição atual (pode ser uma subrequisição, embora) ou a última invocação do comando echo_reset_timer.
O resultado do tempo leva três dígitos após o ponto decimal.
Referências a esta variável forçarão o temporizador subjacente do Nginx a atualizar para o tempo atual do sistema, independentemente das configurações de resolução do temporizador em outro lugar no arquivo de configuração, assim como a diretiva echo_reset_timer.
$echo_request_body
Avalia para o corpo da requisição atual (sub)lido anteriormente se nenhuma parte do corpo foi salva em um arquivo temporário. Para sempre mostrar o corpo da requisição mesmo que seja muito grande, use a diretiva echo_request_body.
$echo_request_method
Avalia para o método de requisição HTTP da requisição atual (pode ser uma subrequisição).
Nos bastidores, ele apenas pega os dados de string armazenados em r->method_name.
Compare isso com a variável $echo_client_request_method.
Pelo menos para o Nginx 0.8.20 e versões anteriores, a variável $request_method fornecida pelo módulo núcleo http está realmente fazendo o que nossa $echo_client_request_method está fazendo.
Esta variável foi introduzida pela primeira vez em nosso lançamento v0.15.
$echo_client_request_method
Sempre avalia para o método HTTP da requisição principal mesmo que a requisição atual seja uma subrequisição.
Nos bastidores, ele apenas pega os dados de string armazenados em r->main->method_name.
Compare isso com a variável $echo_request_method.
Esta variável foi introduzida pela primeira vez em nosso lançamento v0.15.
$echo_client_request_headers
Avalia para os cabeçalhos da requisição original do cliente.
Assim como o nome sugere, sempre tomará a requisição principal (ou a requisição do cliente) mesmo que esteja sendo executada atualmente em uma subrequisição.
Um exemplo simples é abaixo:
location /echoback {
echo "headers are:"
echo $echo_client_request_headers;
}
Acessar /echoback resulta em
$ curl 'http://localhost/echoback'
headers are
GET /echoback HTTP/1.1
User-Agent: curl/7.18.2 (i486-pc-linux-gnu) libcurl/7.18.2 OpenSSL/0.9.8g
Host: localhost:1984
Accept: */*
Nos bastidores, ele recupera r->main->header_in (ou os grandes buffers de cabeçalho, se houver) no nível C e não constrói os cabeçalhos por si mesmo percorrendo os resultados analisados no objeto de requisição.
Esta variável é sempre avaliada como um valor vazio em requisições HTTP/2 por enquanto devido à implementação atual.
Esta variável foi introduzida pela primeira vez na versão 0.15.
$echo_cacheable_request_uri
Avalia para a forma analisada da URI (geralmente precedida por /) da requisição (sub-)atual. Diferente da variável $echo_request_uri, ela é cacheável.
Veja $echo_request_uri para mais detalhes.
Esta variável foi introduzida na versão 0.17.
$echo_request_uri
Avalia para a forma analisada da URI (geralmente precedida por /) da requisição (sub-)atual. Diferente da variável $echo_cacheable_request_uri, ela não é cacheável.
Isso é bastante diferente da variável $request_uri exportada pelo ngx_http_core_module, porque $request_uri é a forma não analisada da URI da requisição atual.
Esta variável foi introduzida na versão 0.17.
$echo_incr
É um contador que sempre gera o número de contagem atual, começando de 1. O contador está sempre associado à requisição principal mesmo que seja acessado dentro de uma subrequisição.
Considere o seguinte exemplo
location /main {
echo "main pre: $echo_incr";
echo_location_async /sub;
echo_location_async /sub;
echo "main post: $echo_incr";
}
location /sub {
echo "sub: $echo_incr";
}
Acessar /main resulta em
main pre: 1
sub: 3
sub: 4
main post: 2
Esta diretiva foi introduzida pela primeira vez no lançamento v0.18.
$echo_response_status
Avalia para o código de status da requisição (sub)atual, nulo se não houver.
Nos bastidores, é apenas a representação textual de r->headers_out->status.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.23.
Módulos que usam este módulo para testes
Os seguintes módulos aproveitam este módulo echo em seu conjunto de testes:
- O módulo memc que suporta quase todo o protocolo TCP do memcached.
- O módulo chunkin que adiciona suporte a entrada chunked HTTP 1.1 ao Nginx.
- O módulo headers_more que permite adicionar, definir e limpar cabeçalhos de entrada e saída sob as condições que você especificar.
- O próprio módulo
echo.
Por favor, envie-me outros módulos que usam echo de qualquer forma e eu os adicionarei à lista acima :)
Mudanças
As mudanças de cada lançamento deste módulo podem ser obtidas nos logs de mudanças do pacote OpenResty:
Conjunto de Testes
Este módulo vem com um conjunto de testes dirigido por Perl. Os casos de teste também são declarativos. Graças ao módulo Test::Nginx no mundo Perl.
Para executá-lo do seu lado:
$ PATH=/path/to/your/nginx-with-echo-module:$PATH prove -r t
Você precisa encerrar qualquer processo do Nginx antes de executar o conjunto de testes se você tiver alterado o binário do servidor Nginx.
Como um único servidor nginx (por padrão, localhost:1984) é usado em todos os scripts de teste (.t), é sem sentido executar o conjunto de testes em paralelo especificando -jN ao invocar a utilidade prove.
Algumas partes do conjunto de testes requerem módulos padrão proxy, rewrite e SSI para serem habilitados também ao construir o Nginx.
Veja Também
- O post do blog original sobre o desenvolvimento inicial deste módulo.
- O padrão módulo de filtro de adição.
- O padrão módulo proxy.
- O OpenResty bundle.
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório GitHub do nginx-module-echo.