echo: módulo Echo de nginx
Instalación
Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:
- RedHat Enterprise Linux 7, 8, 9 y 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 y 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
Habilita el módulo añadiendo lo siguiente al principio de /etc/nginx/nginx.conf:
load_module modules/ngx_http_echo_module.so;
Este documento describe nginx-module-echo v0.64 lanzado el 30 de octubre 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; # asegurar que el cliente pueda ver la salida anterior inmediatamente
echo_sleep 2.5; # en seg
echo world;
}
# en el siguiente ejemplo, acceder a /echo da
# 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;
}
# la salida de /main podría ser
# hello
# world
# took 0.000 sec for total.
# y toda la solicitud tomaría aproximadamente 2 seg para completarse.
location /main {
echo_reset_timer;
# subsolicitudes en 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;
}
# la salida de /main podría ser
# hello
# world
# took 3.003 sec for total.
# y toda la solicitud tomaría aproximadamente 3 seg para completarse.
location /main {
echo_reset_timer;
# subsolicitudes en serie (encadenadas 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;
}
# Acceder a /dup da
# ------ END ------
location /dup {
echo_duplicate 3 "--";
echo_duplicate 1 " END ";
echo_duplicate 3 "--";
echo;
}
# /bighello generará 1000,000,000 hello's.
location /bighello {
echo_duplicate 1000_000_000 'hello';
}
# eco de vuelta la solicitud del cliente
location /echoback {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo_read_request_body;
echo_request_body;
}
# GET /multi dará
# 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 fusionará los 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;
}
# acceder a /if?val=abc da la salida "hit"
# mientras que /if?val=bcd da "miss":
location ^~ /if {
set $res miss;
if ($arg_val ~* '^a') {
set $res hit;
echo $res;
}
echo $res;
}
Descripción
Este módulo envuelve muchas APIs internas de Nginx para la transmisión de entrada y salida, subsolicitudes paralelas/secuenciales, temporizadores y pausas, así como varios accesos a metadatos.
Básicamente, proporciona varias utilidades que ayudan a probar y depurar otros módulos emulando trivialmente diferentes tipos de ubicaciones de subsolicitudes simuladas.
Las personas también lo encontrarán útil en aplicaciones del mundo real que necesitan
- servir contenidos estáticos directamente desde la memoria (cargando desde el archivo de configuración de Nginx).
- envolver la respuesta del upstream con un encabezado y pie de página personalizados (algo así como el módulo de adición pero con contenidos leídos directamente del archivo de configuración y variables de Nginx).
- fusionar contenidos de varias "ubicaciones de Nginx" (es decir, subsolicitudes) en una sola solicitud principal (usando echo_location y sus amigos).
Este es un módulo de doble función especial que puede perezosamente servir como un controlador de contenido o registrarse como un filtro de salida solo bajo demanda. Por defecto, este módulo no hace nada en absoluto.
Técnicamente, este módulo también ha demostrado las siguientes técnicas que podrían ser útiles para los escritores de módulos:
- Emitir subsolicitudes paralelas directamente desde el controlador de contenido.
- Emitir subsolicitudes encadenadas directamente desde el controlador de contenido, pasando la continuación a lo largo de la cadena de subsolicitudes.
- Emitir subsolicitudes con todos los métodos HTTP 1.1 e incluso un cuerpo de solicitud HTTP simulado opcional.
- Interactuar con el modelo de eventos de Nginx directamente desde el controlador de contenido utilizando eventos y temporizadores personalizados, y reanudar el controlador de contenido si es necesario.
- Módulo de doble función que puede (perezosamente) servir como un controlador de contenido o un filtro de salida o ambos.
- Creación e interpolación de variables en el archivo de configuración de Nginx.
- Control de salida en streaming utilizando output_chain, flush y sus amigos.
- Leer el cuerpo de la solicitud del cliente desde el controlador de contenido y regresar (asíncronamente) al controlador de contenido después de la finalización.
- Usar una suite de pruebas declarativa basada en Perl test suite para impulsar el desarrollo de módulos C de Nginx.
Directivas del Controlador de Contenido
El uso de las siguientes directivas registra este módulo en la ubicación actual de Nginx como un controlador de contenido. Si deseas usar otro módulo, como el módulo proxy estándar, como el controlador de contenido, usa las directivas de filtro proporcionadas por este módulo.
Todas las directivas del controlador de contenido se pueden mezclar en una sola ubicación de Nginx y se supone que se ejecutan secuencialmente, al igual que en el lenguaje de scripting Bash.
Cada directiva del controlador de contenido admite la interpolación de variables en sus argumentos (si los hay).
El tipo MIME establecido por la directiva standard default_type es respetado por este módulo, como en:
location /hello {
default_type text/plain;
echo hello;
}
Luego, del lado del 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 la v0.22 en adelante, todas las directivas están permitidas en el bloque de la directiva if del módulo rewrite, por ejemplo:
location ^~ /if {
set $res miss;
if ($arg_val ~* '^a') {
set $res hit;
echo $res;
}
echo $res;
}
echo
syntax: echo [options] <string>...
default: no
context: location, location if
phase: content
Envía argumentos unidos por espacios, junto con una nueva línea final, al cliente.
Ten en cuenta que los datos pueden ser almacenados en el búfer subyacente de Nginx. Para forzar que los datos de salida se envíen inmediatamente, usa el comando echo_flush justo después de echo, como en
echo hello world;
echo_flush;
Cuando no se especifica ningún argumento, echo emite solo la nueva línea final, al igual que el comando echo en shell.
Las variables pueden aparecer en los argumentos. Un ejemplo es
echo The current request uri is $request_uri;
donde $request_uri es una variable expuesta por el ngx_http_core_module.
Este comando se puede usar varias veces en una sola configuración de ubicación, como en
location /echo {
echo hello;
echo world;
}
La salida del lado del cliente se ve así
$ curl 'http://localhost/echo'
hello
world
Los caracteres especiales como nuevas líneas (\n) y tabulaciones (\t) se pueden escapar utilizando secuencias de escape al estilo C. Pero una excepción notable es el signo de dólar ($). A partir de Nginx 0.8.20, aún no hay una forma limpia de escapar este carácter. (Una solución alternativa podría ser usar una variable $echo_dollor que siempre se evalúa como el carácter constante $. Esta función probablemente se introducirá en una versión futura de este módulo.)
A partir de la versión echo v0.28, se puede suprimir el carácter de nueva línea final en la salida utilizando la opción -n, como en
location /echo {
echo -n "hello, ";
echo "world";
}
Acceder a /echo da
$ curl 'http://localhost/echo'
hello, world
El prefijo -n en los valores de las variables no tendrá efecto y se emitirá literalmente, como en
location /echo {
set $opt -n;
echo $opt "hello,";
echo "world";
}
Esto da la siguiente salida
$ curl 'http://localhost/echo'
-n hello,
world
Se puede emitir literales de -n y otras opciones utilizando la opción especial -- de esta manera
location /echo {
echo -- -n is an option;
}
lo que produce
$ curl 'http://localhost/echo'
-n is an option
Usa esta forma cuando quieras emitir cualquier cosa que comience con un guion (-).
echo_duplicate
syntax: echo_duplicate <count> <string>
default: no
context: location, location if
phase: content
Emite duplicados de una cadena indicada por el segundo argumento, usando el conteo especificado en el primer argumento.
Por ejemplo,
location /dup {
echo_duplicate 3 "abc";
}
llevará a la salida de "abcabcabc".
Se permiten guiones bajos en el número de conteo, al igual que en Perl. Por ejemplo, para emitir 1000,000,000 instancias de "hello, world":
location /many_hellos {
echo_duplicate 1000_000_000 "hello, world";
}
El argumento count podría ser cero, pero no negativo. El segundo argumento string también podría ser una cadena vacía ("").
A diferencia de la directiva echo, no se añade una nueva línea final al resultado. Por lo tanto, es posible "abusar" de esta directiva como una versión sin nueva línea final de echo usando "count" 1, como en
location /echo_art {
echo_duplicate 2 '---';
echo_duplicate 1 ' END '; # no queremos una nueva línea final aquí
echo_duplicate 2 '---';
echo; # queremos una nueva línea final aquí...
}
Obtienes
------ END ------
Pero el uso de la opción -n en echo es más apropiado para este propósito.
Esta directiva se introdujo por primera vez en versión 0.11.
echo_flush
syntax: echo_flush
default: no
context: location, location if
phase: content
Forza que los datos potencialmente almacenados en los filtros de salida subyacentes de Nginx se envíen inmediatamente al lado del cliente a través del socket.
Ten en cuenta que técnicamente el comando solo emite un objeto ngx_buf_t con el slot flush establecido en 1, por lo que ciertos módulos de filtro de salida de terceros extraños aún podrían bloquearlo antes de que llegue al filtro de escritura (último) de Nginx.
Esta directiva no toma ningún argumento.
Considera el siguiente ejemplo:
location /flush {
echo hello;
echo_flush;
echo_sleep 1;
echo world;
}
Luego, del lado del cliente, al usar curl para acceder a /flush, verás la línea "hello" de inmediato, pero solo después de 1 segundo, la última línea "world". Sin llamar a echo_flush en el ejemplo anterior, lo más probable es que no veas ninguna salida hasta que transcurra 1 segundo debido al almacenamiento en búfer interno de Nginx.
Esta directiva fallará en vaciar el búfer de salida en caso de que se involucren subsolicitudes. Considera el siguiente ejemplo:
location /main {
echo_location_async /sub;
echo hello;
echo_flush;
}
location /sub {
echo_sleep 1;
}
Entonces el cliente no verá "hello" aparecer incluso si echo_flush se ha ejecutado antes de que la subsolicitud a /sub haya comenzado a ejecutarse. Las salidas de /main que se envían después de echo_location_async se pospondrán y se almacenarán firmemente en búfer.
Esto no se aplica a las salidas enviadas antes de que se inicie la subsolicitud. Para una versión modificada del ejemplo dado anteriormente:
location /main {
echo hello;
echo_flush;
echo_location_async /sub;
}
location /sub {
echo_sleep 1;
}
El cliente verá inmediatamente "hello" antes de que /sub entre en estado de sueño.
Consulta también echo, echo_sleep y echo_location_async.
echo_sleep
syntax: echo_sleep <seconds>
default: no
context: location, location if
phase: content
Duerme durante el período de tiempo especificado por el argumento, que está en segundos.
Esta operación no bloquea el lado del servidor, por lo que a diferencia de la directiva echo_blocking_sleep, no bloqueará todo el proceso de trabajo de Nginx.
El período puede tener tres dígitos después del punto decimal y debe ser mayor que 0.001.
Un ejemplo es
location /echo_after_sleep {
echo_sleep 1.234;
echo resumed!;
}
Detrás de escena, configura un objeto "sleep" ngx_event_t por solicitud y añade un temporizador utilizando ese evento personalizado al modelo de eventos de Nginx y solo espera un tiempo de espera en ese evento. Debido a que el evento "sleep" es por solicitud, esta directiva puede funcionar en subsolicitudes paralelas.
echo_blocking_sleep
syntax: echo_blocking_sleep <seconds>
default: no
context: location, location if
phase: content
Esta es una versión bloqueante de la directiva echo_sleep.
Consulta la documentación de echo_sleep para más detalles.
Detrás de escena, llama a la macro ngx_msleep proporcionada por el núcleo de Nginx que se mapea a usleep en sistemas compatibles con POSIX.
Ten en cuenta que esta directiva bloqueará completamente el proceso de trabajo actual de Nginx mientras se ejecuta, así que nunca la uses en un entorno de producción.
echo_reset_timer
syntax: echo_reset_timer
default: no
context: location, location if
phase: content
Restablece el tiempo de inicio del temporizador a ahora, es decir, el tiempo cuando se ejecuta este comando durante la solicitud.
El tiempo de inicio del temporizador se establece por defecto en el tiempo de inicio de la solicitud actual y puede ser sobrescrito por esta directiva, potencialmente múltiples veces en una sola ubicación. Por ejemplo:
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.";
}
La salida del lado del cliente podría ser
$ curl 'http://localhost/timed_sleep'
0.032 sec elapsed.
0.020 sec elapsed.
Las cifras reales que obtienes de tu lado pueden variar un poco debido a las actividades actuales de tu sistema.
La invocación de esta directiva forzará a que el temporizador subyacente de Nginx se actualice al tiempo del sistema actual (independientemente de la resolución del temporizador especificada en otro lugar en el archivo de configuración). Además, las referencias de la variable $echo_timer_elapsed también forzarán la actualización del temporizador.
Consulta también echo_sleep y $echo_timer_elapsed.
echo_read_request_body
syntax: echo_read_request_body
default: no
context: location, location if
phase: content
Lee explícitamente el cuerpo de la solicitud para que la variable $request_body siempre tenga valores no vacíos (a menos que el cuerpo sea tan grande que ha sido guardado por Nginx en un archivo temporal local).
Ten en cuenta que esto podría no ser el cuerpo original de la solicitud del cliente porque la solicitud actual podría ser una subsolicitud con un cuerpo "artificial" especificado por su padre.
Esta directiva no genera ninguna salida por sí misma, al igual que echo_sleep.
Aquí hay un ejemplo para eco de vuelta la solicitud HTTP original del cliente (se incluyen tanto los encabezados como el cuerpo):
location /echoback {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo_read_request_body;
echo $request_body;
}
El contenido de /echoback se ve así en mi lado (estaba usando la utilidad LWP de Perl para acceder a esta ubicación en el 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
Debido a que /echoback es la solicitud principal, $request_body contiene el cuerpo original de la solicitud del cliente.
Antes de Nginx 0.7.56, no tenía sentido usar esta directiva porque $request_body se introdujo por primera vez en Nginx 0.7.58.
Esta directiva en sí se introdujo por primera vez en la v0.14 release del módulo echo.
echo_location_async
syntax: echo_location_async <location> [<url_args>]
default: no
context: location, location if
phase: content
Emite una subsolicitud GET a la ubicación especificada (primer argumento) con argumentos de URL opcionales especificados en el segundo argumento.
A partir de Nginx 0.8.20, el argumento location no admite ubicaciones nombradas, debido a una limitación en la función ngx_http_subrequest. Lo mismo es cierto para su hermano, la directiva echo_location.
Un ejemplo muy simple es
location /main {
echo_location_async /sub;
echo world;
}
location /sub {
echo hello;
}
Acceder a /main da
hello
world
Llamar a múltiples ubicaciones en paralelo también es posible:
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; # duerme 2 seg
echo hello;
}
location /sub2 {
echo_sleep 1; # duerme 1 seg
echo world;
}
Acceder a /main produce
$ time curl 'http://localhost/main'
hello
world
took 0.000 sec for total.
real 0m2.006s
user 0m0.000s
sys 0m0.004s
Puedes ver que el controlador principal /main no espera a que las subsolicitudes /sub1 y /sub2 se completen y continúa rápidamente, de ahí el resultado de tiempo "0.000 sec". Sin embargo, toda la solicitud toma aproximadamente 2 seg en total para completarse porque /sub1 y /sub2 se ejecutan en paralelo (o "concurrentemente" para ser más precisos).
Si usas echo_blocking_sleep en el ejemplo anterior, obtendrás la misma salida, pero con un tiempo de respuesta total de 3 seg, porque "sleep bloqueante" bloquea todo el proceso de trabajo de Nginx.
Las ubicaciones también pueden tomar un argumento de cadena de consulta opcional, por ejemplo
location /main {
echo_location_async /sub 'foo=Foo&bar=Bar';
}
location /sub {
echo $arg_foo $arg_bar;
}
Acceder a /main produce
$ curl 'http://localhost/main'
Foo Bar
Las cadenas de consulta no se permiten concatenar al argumento location con "?" directamente, por ejemplo, /sub?foo=Foo&bar=Bar es una ubicación no válida y no debería ser alimentada como el primer argumento a esta directiva.
Técnicamente hablando, esta directiva es un ejemplo de que el controlador de contenido de Nginx emite una o más subsolicitudes directamente. Hasta donde sé, el módulo fancyindex también hace este tipo de cosas ;)
Las ubicaciones nombradas de Nginx como @foo no son compatibles aquí.
Esta directiva es lógicamente equivalente a la versión GET de echo_subrequest_async. Por ejemplo,
echo_location_async /foo 'bar=Bar';
es lógicamente equivalente a
echo_subrequest_async GET /foo -q 'bar=Bar';
Pero llamar a esta directiva es ligeramente más rápido que llamar a echo_subrequest_async usando GET porque no tenemos que analizar los nombres de los métodos HTTP como GET y opciones como -q.
Esta directiva se introdujo por primera vez en versión 0.09 de este módulo y requiere al menos Nginx 0.7.46.
echo_location
syntax: echo_location <location> [<url_args>]
default: no
context: location, location if
phase: content
Al igual que la directiva echo_location_async, pero echo_location emite subsolicitudes en serie en lugar de en paralelo. Es decir, las directivas del controlador de contenido que siguen a esta directiva no se ejecutarán hasta que la subsolicitud emitida por esta directiva se complete.
El cuerpo de respuesta final es casi siempre equivalente al caso cuando se usa echo_location_async en su lugar, solo si se utilizan variables de tiempo en las salidas.
Considera el siguiente ejemplo:
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;
}
La ubicación /main anterior tomará un total de 3 seg para completarse (en comparación con 2 seg si se usa echo_location_async en su lugar). Aquí está el resultado en acción en mi máquina:
$ curl 'http://localhost/main'
hello
world
took 3.003 sec for total.
real 0m3.027s
user 0m0.020s
sys 0m0.004s
Esta directiva es lógicamente equivalente a la versión GET de echo_subrequest. Por ejemplo,
echo_location /foo 'bar=Bar';
es lógicamente equivalente a
echo_subrequest GET /foo -q 'bar=Bar';
Pero llamar a esta directiva es ligeramente más rápido que llamar a echo_subrequest usando GET porque no tenemos que analizar los nombres de los métodos HTTP como GET y opciones como -q.
Detrás de escena, crea un objeto ngx_http_post_subrequest_t como una continuación y lo pasa a la llamada de función ngx_http_subrequest. Nginx más tarde reabrirá esta "continuación" en la llamada de función ngx_http_finalize_request de la subsolicitud. Reanudamos la ejecución del controlador de contenido de la solicitud principal y comenzamos a ejecutar la siguiente directiva (comando) si hay alguna.
Las ubicaciones nombradas de Nginx como @foo no son compatibles aquí.
Esta directiva se introdujo por primera vez en la release v0.12.
Consulta también echo_location_async para más detalles sobre el significado de los argumentos.
echo_subrequest_async
syntax: echo_subrequest_async <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]
default: no
context: location, location if
phase: content
Inicia una subsolicitud asíncrona utilizando el método HTTP, argumentos de URL opcionales (o cadena de consulta) y un cuerpo de solicitud opcional que puede definirse como una cadena o como una ruta a un archivo que contiene el cuerpo.
Esta directiva es muy similar a una versión generalizada de la directiva echo_location_async.
Aquí hay un pequeño ejemplo que demuestra su uso:
location /multi {
# cuerpo definido como cadena
echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi';
# cuerpo definido como ruta a un archivo, relativo a la ruta de prefijo de nginx si no es 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 '///';
}
Luego, del lado del 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
///
Aquí hay un ejemplo más divertido usando el módulo proxy estándar proxy module para manejar la subsolicitud:
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.";
# necesitamos leer el cuerpo aquí explícitamente...o $echo_request_body
# se evaluará como vacío ("")
echo_read_request_body;
echo "body: $echo_request_body.";
}
Luego, del lado del cliente, podemos ver que
$ curl 'http://localhost/main'
method: POST.
body: hello, world.
Las ubicaciones nombradas de Nginx como @foo no son compatibles aquí.
Esta directiva toma varias opciones:
-q <url_args> Especifica los argumentos de URL (o cadena de consulta) para la subsolicitud.
-f <path> Especifica la ruta para el archivo cuyo contenido se servirá como el
cuerpo de la solicitud de la subsolicitud.
-b <data> Especifica los datos del cuerpo de la solicitud.
Esta directiva se introdujo por primera vez en la release v0.15.
La opción -f para definir una ruta de archivo para el cuerpo se introdujo en la release v0.35.
Consulta también las directivas echo_subrequest y echo_location_async.
echo_subrequest
syntax: echo_subrequest <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]
default: no
context: location, location if
phase: content
Esta es la versión sincrónica de la directiva echo_subrequest_async. Y al igual que echo_location, no bloquea el proceso de trabajo de Nginx (mientras que echo_blocking_sleep sí lo hace), sino que utiliza la continuación para pasar el control a lo largo de la cadena de subsolicitudes.
Consulta echo_subrequest_async para más detalles.
Las ubicaciones nombradas de Nginx como @foo no son compatibles aquí.
Esta directiva se introdujo por primera vez en la release v0.15.
echo_foreach_split
syntax: echo_foreach_split <delimiter> <string>
default: no
context: location, location if
phase: content
Divide el segundo argumento string utilizando el delimitador especificado en el primer argumento, y luego itera a través de los elementos resultantes. Por ejemplo:
location /loop {
echo_foreach_split ',' $arg_list;
echo "item: $echo_it";
echo_end;
}
Acceder a /main produce
$ curl 'http://localhost/loop?list=cat,dog,mouse'
item: cat
item: dog
item: mouse
Como se vio en el ejemplo anterior, esta directiva siempre debe ir acompañada de una directiva echo_end.
Se permiten bucles paralelos echo_foreach_split, pero los anidados están actualmente prohibidos.
El argumento delimiter podría contener múltiples caracteres arbitrarios, como
# esto produce "cat\ndog\nmouse\n"
echo_foreach_split -- '-a-' 'cat-a-dog-a-mouse';
echo $echo_it;
echo_end;
Hablando lógicamente, esta estructura de bucle es solo el bucle foreach combinado con una llamada a la función split en Perl (usando el ejemplo anterior):
foreach (split ',', $arg_list) {
print "item $_\n";
}
Las personas también lo encontrarán útil para fusionar múltiples recursos .js o .css en un todo. Aquí hay un ejemplo:
location /merge {
default_type 'text/javascript';
echo_foreach_split '&' $query_string;
echo "/* JS File $echo_it */";
echo_location_async $echo_it;
echo;
echo_end;
}
Luego, al acceder a /merge para fusionar los recursos .js especificados en la cadena de consulta:
$ curl 'http://localhost/merge?/foo/bar.js&/yui/blah.js&/baz.js'
También se puede usar un módulo de caché de Nginx de terceros para almacenar en caché la respuesta fusionada generada por la ubicación /merge en el ejemplo anterior.
Esta directiva se introdujo por primera vez en la release v0.17.
echo_end
syntax: echo_end
default: no
context: location, location if
phase: content
Esta directiva se utiliza para terminar el cuerpo de estructuras de control de bucle y condicionales como echo_foreach_split.
Esta directiva se introdujo por primera vez en la release v0.17.
echo_request_body
syntax: echo_request_body
default: no
context: location, location if
phase: content
Emite el contenido del cuerpo de la solicitud leído previamente.
Detrás de escena, se implementa aproximadamente así:
if (r->request_body && r->request_body->bufs) {
return ngx_http_output_filter(r, r->request_body->bufs);
}
A diferencia de las variables $echo_request_body y $request_body, esta directiva mostrará todo el cuerpo de la solicitud incluso si algunas partes o todas las partes se han guardado en archivos temporales en el disco.
Es un "no-op" si no se ha leído ningún cuerpo de solicitud aún.
Esta directiva se introdujo por primera vez en la release v0.18.
Consulta también echo_read_request_body y el módulo chunkin.
echo_exec
syntax: echo_exec <location> [<query_string>]
syntax: echo_exec <named_location>
default: no
context: location, location if
phase: content
Realiza una redirección interna a la ubicación especificada. Se puede especificar una cadena de consulta opcional para ubicaciones normales, como en
location /foo {
echo_exec /bar weight=5;
}
location /bar {
echo $arg_weight;
}
O de manera equivalente
location /foo {
echo_exec /bar?weight=5;
}
location /bar {
echo $arg_weight;
}
Las ubicaciones nombradas también son compatibles. Aquí hay un ejemplo:
location /foo {
echo_exec @bar;
}
location @bar {
# obtendrás /foo en lugar de @bar
# debido a un posible error en nginx.
echo $echo_request_uri;
}
Pero la cadena de consulta (si la hay) siempre se ignorará para las redirecciones de ubicación nombrada debido a una limitación en la función ngx_http_named_location.
Nunca intentes eco de cosas antes de la directiva echo_exec o no verás la respuesta adecuada de la ubicación a la que deseas redirigir. Porque cualquier eco causará que el controlador de la ubicación original envíe encabezados HTTP antes de que ocurra la redirección.
Técnicamente hablando, esta directiva expone las funciones de API internas de Nginx ngx_http_internal_redirect y ngx_http_named_location.
Esta directiva se introdujo por primera vez en la v0.21 release.
echo_status
syntax: echo_status <status-num>
default: echo_status 200
context: location, location if
phase: content
Especifica el código de estado de respuesta predeterminado. Por defecto es 200. Esta directiva es declarativa y el orden relativo con otras directivas similares a echo no es importante.
Aquí hay un ejemplo,
location = /bad {
echo_status 404;
echo "Something is missing...";
}
entonces obtenemos una respuesta como esta:
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 directiva se introdujo por primera vez en la release v0.40.
Directivas de Filtro
El uso de las siguientes directivas activa el registro de filtros de este módulo. Por defecto, ningún filtro será registrado por este módulo.
Cada directiva de filtro admite la interpolación de variables en sus argumentos (si los hay).
echo_before_body
syntax: echo_before_body [options] [argument]...
default: no
context: location, location if
phase: output filter
Es la versión de filtro de la directiva echo y antepone su salida al principio de las salidas originales generadas por el controlador de contenido subyacente.
Un ejemplo es
location /echo {
echo_before_body hello;
proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more;
}
location /echo/more {
echo world
}
Acceder a /echo desde el lado del cliente produce
hello
world
En el ejemplo anterior, tomamos prestado el módulo proxy estándar para servir como el controlador de contenido subyacente que genera los "contenidos principales".
Se permiten múltiples instancias de esta directiva de filtro, como en:
location /echo {
echo_before_body hello;
echo_before_body world;
echo !;
}
Del lado del cliente, la salida es como
$ curl 'http://localhost/echo'
hello
world
!
En este ejemplo, también usamos las directivas del controlador de contenido proporcionadas por este módulo como el controlador de contenido subyacente.
Esta directiva también admite las opciones -n y -- como la directiva echo.
Esta directiva se puede mezclar con su directiva hermana echo_after_body.
echo_after_body
syntax: echo_after_body [argument]...
default: no
context: location, location if
phase: output filter
Es muy similar a la directiva echo_before_body, pero añade su salida al final de las salidas originales generadas por el controlador de contenido subyacente.
Aquí hay un ejemplo simple:
location /echo {
echo_after_body hello;
proxy_pass http://127.0.0.1:$server_port$request_uri/more;
}
location /echo/more {
echo world
}
Acceder a /echo desde el lado del cliente produce
world
hello
Se permiten múltiples instancias, como en:
location /echo {
echo_after_body hello;
echo_after_body world;
echo i;
echo say;
}
La salida del lado del cliente al acceder a la ubicación /echo se ve así
i
say
hello
world
Esta directiva también admite las opciones -n y -- como la directiva echo.
Esta directiva se puede mezclar con su directiva hermana echo_before_body.
Variables
$echo_it
Esta es una "variable de tema" utilizada por echo_foreach_split, al igual que la variable $_ en Perl.
$echo_timer_elapsed
Esta variable contiene los segundos transcurridos desde el inicio de la solicitud actual (podría ser una subsolicitud, sin embargo) o la última invocación del comando echo_reset_timer.
El resultado del tiempo toma tres dígitos después del punto decimal.
Las referencias a esta variable forzarán al temporizador subyacente de Nginx a actualizarse al tiempo del sistema actual, independientemente de la configuración de resolución del temporizador en otro lugar en el archivo de configuración, al igual que la directiva echo_reset_timer.
$echo_request_body
Se evalúa como el cuerpo de la solicitud actual (sub) leído previamente si ninguna parte del cuerpo ha sido guardada en un archivo temporal. Para mostrar siempre el cuerpo de la solicitud incluso si es muy grande, usa la directiva echo_request_body.
$echo_request_method
Se evalúa como el método de solicitud HTTP de la solicitud actual (puede ser una subsolicitud).
Detrás de escena, simplemente toma los datos de cadena almacenados en r->method_name.
Compáralo con la variable $echo_client_request_method.
Al menos para Nginx 0.8.20 y versiones anteriores, la variable $request_method proporcionada por el módulo núcleo http está haciendo lo que nuestra $echo_client_request_method está haciendo.
Esta variable se introdujo por primera vez en nuestra v0.15 release.
$echo_client_request_method
Siempre se evalúa como el método HTTP de la solicitud principal incluso si la solicitud actual es una subsolicitud.
Detrás de escena, simplemente toma los datos de cadena almacenados en r->main->method_name.
Compáralo con la variable $echo_request_method.
Esta variable se introdujo por primera vez en nuestra v0.15 release.
$echo_client_request_headers
Se evalúa como los encabezados de la solicitud original del cliente.
Tal como su nombre sugiere, siempre tomará la solicitud principal (o la solicitud del cliente) incluso si se está ejecutando actualmente en una subsolicitud.
Un ejemplo simple es el siguiente:
location /echoback {
echo "headers are:"
echo $echo_client_request_headers;
}
Acceder a /echoback produce
$ 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: */*
Detrás de escena, recupera r->main->header_in (o los grandes búferes de encabezados, si los hay) a nivel C y no construye los encabezados por sí mismo al recorrer los resultados analizados en el objeto de solicitud.
Esta variable siempre se evalúa a un valor vacío en solicitudes HTTP/2 por ahora debido a la implementación actual.
Esta variable se introdujo por primera vez en versión 0.15.
$echo_cacheable_request_uri
Se evalúa como la forma analizada de la URI (generalmente precedida por /) de la solicitud (sub)actual. A diferencia de la variable $echo_request_uri, es cacheable.
Consulta $echo_request_uri para más detalles.
Esta variable se introdujo por primera vez en versión 0.17.
$echo_request_uri
Se evalúa como la forma analizada de la URI (generalmente precedida por /) de la solicitud (sub)actual. A diferencia de la variable $echo_cacheable_request_uri, no es cacheable.
Esto es bastante diferente de la variable $request_uri exportada por el ngx_http_core_module, porque $request_uri es la forma no analizada de la URI de la solicitud actual.
Esta variable se introdujo en versión 0.17.
$echo_incr
Es un contador que siempre genera el número de conteo actual, comenzando desde 1. El contador siempre está asociado con la solicitud principal incluso si se accede dentro de una subsolicitud.
Considera el siguiente ejemplo
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";
}
Acceder a /main produce
main pre: 1
sub: 3
sub: 4
main post: 2
Esta directiva se introdujo por primera vez en la v0.18 release.
$echo_response_status
Se evalúa como el código de estado de la solicitud (sub)actual, nulo si no hay ninguno.
Detrás de escena, es simplemente la representación textual de r->headers_out->status.
Esta directiva se introdujo por primera vez en la v0.23 release.
Módulos que utilizan este módulo para pruebas
Los siguientes módulos aprovechan este módulo echo en su suite de pruebas:
- El módulo memc que admite casi todo el protocolo TCP de memcached.
- El módulo chunkin que agrega soporte de entrada en fragmentos HTTP 1.1 a Nginx.
- El módulo headers_more que te permite agregar, establecer y borrar encabezados de entrada y salida bajo las condiciones que especifiques.
- El módulo
echoen sí.
Por favor, envíame otros módulos que usen echo en cualquier forma y los agregaré a la lista anterior :)
Cambios
Los cambios de cada lanzamiento de este módulo se pueden obtener de los registros de cambios del paquete OpenResty:
Suite de Pruebas
Este módulo viene con una suite de pruebas impulsada por Perl. Los casos de prueba son también declarativos. Gracias al módulo Test::Nginx en el mundo Perl.
Para ejecutarlo en tu lado:
$ PATH=/path/to/your/nginx-with-echo-module:$PATH prove -r t
Necesitas terminar cualquier proceso de Nginx antes de ejecutar la suite de pruebas si has cambiado el binario del servidor Nginx.
Debido a que un solo servidor nginx (por defecto, localhost:1984) se utiliza en todos los scripts de prueba (.t), no tiene sentido ejecutar la suite de pruebas en paralelo especificando -jN al invocar la utilidad prove.
Algunas partes de la suite de pruebas requieren que se habiliten los módulos estándar proxy, rewrite y SSI también al construir Nginx.
Ver También
- La publicación original en el blog sobre el desarrollo inicial de este módulo.
- El módulo de filtro estándar addition filter module.
- El módulo estándar proxy module.
- El paquete OpenResty.
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-echo.