echo: NGINX Echo-Modul
Installation
Sie können dieses Modul in jeder RHEL-basierten Distribution installieren, einschließlich, aber nicht beschränkt auf:
- RedHat Enterprise Linux 7, 8, 9 und 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 und 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
Aktivieren Sie das Modul, indem Sie Folgendes an den Anfang von /etc/nginx/nginx.conf hinzufügen:
load_module modules/ngx_http_echo_module.so;
Dieses Dokument beschreibt nginx-module-echo v0.65 veröffentlicht am 07. Juni 2026.
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;
}
# im folgenden Beispiel ergibt der Zugriff auf /echo
# 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;
}
# die Ausgabe von /main könnte sein
# hello
# world
# took 0.000 sec for total.
# und die gesamte Anfrage würde etwa 2 Sekunden dauern, um abzuschließen.
location /main {
echo_reset_timer;
# Subanfragen parallel
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;
}
# die Ausgabe von /main könnte sein
# hello
# world
# took 3.003 sec for total.
# und die gesamte Anfrage würde etwa 3 Sekunden dauern, um abzuschließen.
location /main {
echo_reset_timer;
# Subanfragen in Serie (verknüpft durch 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;
}
# Der Zugriff auf /dup ergibt
# ------ END ------
location /dup {
echo_duplicate 3 "--";
echo_duplicate 1 " END ";
echo_duplicate 3 "--";
echo;
}
# /bighello wird 1000.000.000 hello's generieren.
location /bighello {
echo_duplicate 1000_000_000 'hello';
}
# echo gibt die Client-Anfrage zurück
location /echoback {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo_read_request_body;
echo_request_body;
}
# GET /multi ergibt
# 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 wird die .js-Ressourcen zusammenführen
location /merge {
default_type 'text/javascript';
echo_foreach_split '&' $query_string;
echo "/* JS File $echo_it */";
echo_location_async $echo_it;
echo;
echo_end;
}
# der Zugriff auf /if?val=abc ergibt die "hit"-Ausgabe
# während /if?val=bcd "miss" ergibt:
location ^~ /if {
set $res miss;
if ($arg_val ~* '^a') {
set $res hit;
echo $res;
}
echo $res;
}
Beschreibung
Dieses Modul umschließt viele interne NGINX-APIs für Streaming-Eingaben und -Ausgaben, parallele/sequenzielle Subanfragen, Timer und Schlaf sowie den Zugriff auf verschiedene Metadaten.
Grundsätzlich bietet es verschiedene Dienstprogramme, die beim Testen und Debuggen anderer Module helfen, indem sie verschiedene Arten von gefälschten Subanfrage-Standorten trivial emulieren.
Die Leute werden es auch in realen Anwendungen nützlich finden, die
- statische Inhalte direkt aus dem Speicher bereitstellen müssen (Laden aus der NGINX-Konfigurationsdatei).
- die Antwort des Upstreams mit benutzerdefinierten Kopf- und Fußzeilen umhüllen müssen (ähnlich wie das Addition-Modul, aber mit Inhalten, die direkt aus der Konfigurationsdatei und NGINX-Variablen gelesen werden).
- Inhalte verschiedener "NGINX-Standorte" (d.h. Subanfragen) in einer einzigen Hauptanfrage zusammenführen müssen (unter Verwendung von echo_location und seinen Freunden).
Dies ist ein spezielles Dual-Rollen-Modul, das faul als Inhalts-Handler dienen oder sich nur auf Anfrage als Ausgabefilter registrieren kann. Standardmäßig tut dieses Modul überhaupt nichts.
Technisch hat dieses Modul auch die folgenden Techniken demonstriert, die für Modulautoren hilfreich sein könnten:
- Parallel Subanfragen direkt vom Inhalts-Handler ausstellen.
- Verkettete Subanfragen direkt vom Inhalts-Handler ausstellen, indem die Fortsetzung entlang der Subanfrage-Kette übergeben wird.
- Subanfragen mit allen HTTP 1.1-Methoden und sogar einem optionalen gefälschten HTTP-Anforderungstext ausstellen.
- Direkt mit dem NGINX-Ereignismodell vom Inhalts-Handler aus interagieren, indem benutzerdefinierte Ereignisse und Timer verwendet werden, und den Inhalts-Handler bei Bedarf wieder aufnehmen.
- Dual-Rollen-Modul, das (faul) als Inhalts-Handler oder Ausgabefilter oder beides dienen kann.
- Erstellung und Interpolation von NGINX-Konfigurationsdatei-Variablen.
- Streaming-Ausgabesteuerung mit output_chain, flush und seinen Freunden.
- Den Anforderungstext des Clients vom Inhalts-Handler lesen und (asynchron) an den Inhalts-Handler zurückgeben, nachdem die Verarbeitung abgeschlossen ist.
- Verwenden Sie die auf Perl basierende deklarative Test-Suite, um die Entwicklung von NGINX-C-Modulen voranzutreiben.
Inhalts-Handler-Direktiven
Die Verwendung der folgenden Direktiven registriert dieses Modul als Inhalts-Handler für den aktuellen NGINX-Standort. Wenn Sie ein anderes Modul verwenden möchten, wie das Standard-Proxy-Modul, als Inhalts-Handler, verwenden Sie die von diesem Modul bereitgestellten Filter-Direktiven.
Alle Inhalts-Handler-Direktiven können in einem einzigen NGINX-Standort gemischt werden, und sie sollen sequenziell ausgeführt werden, genau wie in der Bash-Skriptsprache.
Jede Inhalts-Handler-Direktive unterstützt die Variableninterpolation in ihren Argumenten (sofern vorhanden).
Der MIME-Typ, der durch die Standard-default_type-Direktive festgelegt wird, wird von diesem Modul respektiert, wie in:
location /hello {
default_type text/plain;
echo hello;
}
Dann auf der Client-Seite:
$ 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
Seit der v0.22-Version sind alle Direktiven im Block der if-Direktive des Rewrite-Moduls erlaubt, zum Beispiel:
location ^~ /if {
set $res miss;
if ($arg_val ~* '^a') {
set $res hit;
echo $res;
}
echo $res;
}
echo
syntax: echo [options] <string>...
default: nein
context: location, location if
phase: content
Sendet Argumente, die durch Leerzeichen verbunden sind, zusammen mit einer abschließenden neuen Zeile an den Client.
Beachten Sie, dass die Daten möglicherweise von NGINXs zugrunde liegendem Puffer gepuffert werden. Um sicherzustellen, dass die Ausgabedaten sofort ausgegeben werden, verwenden Sie den Befehl echo_flush direkt nach echo, wie in
echo hello world;
echo_flush;
Wenn kein Argument angegeben ist, gibt echo nur die abschließende neue Zeile aus, genau wie der echo-Befehl in der Shell.
Variablen können in den Argumenten erscheinen. Ein Beispiel ist
echo The current request uri is $request_uri;
wo $request_uri eine von dem ngx_http_core_module bereitgestellte Variable ist.
Dieser Befehl kann in einer einzigen Standortkonfiguration mehrfach verwendet werden, wie in
location /echo {
echo hello;
echo world;
}
Die Ausgabe auf der Client-Seite sieht so aus
$ curl 'http://localhost/echo'
hello
world
Sonderzeichen wie neue Zeilen (\n) und Tabs (\t) können mit C-ähnlichen Escape-Sequenzen escaped werden. Eine bemerkenswerte Ausnahme ist jedoch das Dollarzeichen ($). Seit NGINX 0.8.20 gibt es immer noch keinen sauberen Weg, dieses Zeichen zu escapen. (Ein Workaround könnte sein, eine $echo_dollor-Variable zu verwenden, die immer auf das konstante $-Zeichen ausgewertet wird. Diese Funktion wird möglicherweise in einer zukünftigen Version dieses Moduls eingeführt.)
Seit der echo v0.28-Version kann man das abschließende neue Zeilenzeichen in der Ausgabe unterdrücken, indem man die -n-Option verwendet, wie in
location /echo {
echo -n "hello, ";
echo "world";
}
Der Zugriff auf /echo ergibt
$ curl 'http://localhost/echo'
hello, world
Führende -n in Variablenwerten haben keine Wirkung und werden wörtlich ausgegeben, wie in
location /echo {
set $opt -n;
echo $opt "hello,";
echo "world";
}
Dies ergibt die folgende Ausgabe
$ curl 'http://localhost/echo'
-n hello,
world
Man kann führende -n Literale und andere Optionen mit der speziellen ---Option so ausgeben
location /echo {
echo -- -n is an option;
}
was ergibt
$ curl 'http://localhost/echo'
-n is an option
Verwenden Sie diese Form, wenn Sie alles ausgeben möchten, was mit einem Bindestrich (-) beginnt.
echo_duplicate
syntax: echo_duplicate <count> <string>
default: nein
context: location, location if
phase: content
Gibt eine Duplikation eines durch das zweite Argument angegebenen Strings aus, wobei die im ersten Argument angegebene Anzahl verwendet wird.
Zum Beispiel,
location /dup {
echo_duplicate 3 "abc";
}
führt zur Ausgabe von "abcabcabc".
Unterstriche sind in der Zählzahl erlaubt, genau wie in Perl. Um beispielsweise 1000.000.000 Instanzen von "hello, world" auszugeben:
location /many_hellos {
echo_duplicate 1000_000_000 "hello, world";
}
Das count-Argument könnte null sein, aber nicht negativ. Das zweite string-Argument könnte ebenfalls ein leerer String ("") sein.
Im Gegensatz zur echo-Direktive wird kein abschließendes neues Zeilenzeichen an das Ergebnis angehängt. Daher ist es möglich, diese Direktive als eine Version von echo ohne abschließende neue Zeile zu "missbrauchen", indem man "count" 1 verwendet, wie in
location /echo_art {
echo_duplicate 2 '---';
echo_duplicate 1 ' END '; # wir wollen hier keine abschließende neue Zeile
echo_duplicate 2 '---';
echo; # wir wollen hier eine abschließende neue Zeile...
}
Sie erhalten
------ END ------
Aber die Verwendung der -n-Option in echo ist für diesen Zweck geeigneter.
Diese Direktive wurde erstmals in der Version 0.11 eingeführt.
echo_flush
syntax: echo_flush
default: nein
context: location, location if
phase: content
Zwingt die möglicherweise von zugrunde liegenden NGINX-Ausgabefiltern gepufferten Daten, sofort an die Client-Seite über den Socket zu senden.
Beachten Sie, dass der Befehl technisch gesehen nur ein ngx_buf_t-Objekt mit dem flush-Slot, der auf 1 gesetzt ist, ausgibt, sodass bestimmte seltsame Drittanbieter-Ausgabefiltermodule es möglicherweise weiterhin blockieren, bevor es NGINXs (letztem) Schreibfilter erreicht.
Diese Direktive benötigt keine Argumente.
Betrachten Sie das folgende Beispiel:
location /flush {
echo hello;
echo_flush;
echo_sleep 1;
echo world;
}
Dann sehen Sie auf der Client-Seite, wenn Sie /flush mit curl aufrufen, die "hello"-Zeile sofort, aber erst nach 1 Sekunde die letzte "world"-Zeile. Ohne den Aufruf von echo_flush im obigen Beispiel sehen Sie wahrscheinlich keine Ausgabe, bis 1 Sekunde vergangen ist, aufgrund der internen Pufferung von NGINX.
Diese Direktive wird den Ausgabepuffer nicht leeren, wenn Subanfragen beteiligt sind. Betrachten Sie das folgende Beispiel:
location /main {
echo_location_async /sub;
echo hello;
echo_flush;
}
location /sub {
echo_sleep 1;
}
Dann wird der Client "hello" nicht sehen, auch wenn echo_flush vor dem Start der Subanfrage zu /sub ausgeführt wurde. Die Ausgaben von /main, die nach echo_location_async gesendet werden, werden aufgeschoben und fest gepuffert.
Dies gilt nicht für Ausgaben, die vor der Initiierung der Subanfrage gesendet wurden. Für eine modifizierte Version des obigen Beispiels:
location /main {
echo hello;
echo_flush;
echo_location_async /sub;
}
location /sub {
echo_sleep 1;
}
Der Client wird sofort "hello" sehen, bevor /sub in den Schlafzustand übergeht.
Siehe auch echo, echo_sleep und echo_location_async.
echo_sleep
syntax: echo_sleep <seconds>
default: nein
context: location, location if
phase: content
Schläft für den im Argument angegebenen Zeitraum, der in Sekunden angegeben ist.
Dieser Vorgang ist nicht blockierend auf der Serverseite, sodass er im Gegensatz zur echo_blocking_sleep-Direktive den gesamten NGINX-Worker-Prozess nicht blockiert.
Der Zeitraum kann drei Ziffern nach dem Dezimalpunkt haben und muss größer als 0.001 sein.
Ein Beispiel ist
location /echo_after_sleep {
echo_sleep 1.234;
echo resumed!;
}
Im Hintergrund richtet es ein pro-Anfrage "sleep" ngx_event_t-Objekt ein und fügt einen Timer mit diesem benutzerdefinierten Ereignis zum NGINX-Ereignismodell hinzu und wartet einfach auf einen Timeout bei diesem Ereignis. Da das "sleep"-Ereignis pro Anfrage ist, kann diese Direktive in parallelen Subanfragen funktionieren.
echo_blocking_sleep
syntax: echo_blocking_sleep <seconds>
default: nein
context: location, location if
phase: content
Dies ist eine blockierende Version der echo_sleep-Direktive.
Siehe die Dokumentation von echo_sleep für mehr Details.
Im Hintergrund ruft es das ngx_msleep-Makro auf, das vom NGINX-Kern bereitgestellt wird und auf POSIX-konformen Systemen zu usleep abgebildet wird.
Beachten Sie, dass diese Direktive den aktuellen NGINX-Worker-Prozess während der Ausführung vollständig blockiert, verwenden Sie sie also niemals in einer Produktionsumgebung.
echo_reset_timer
syntax: echo_reset_timer
default: nein
context: location, location if
phase: content
Setzt die Timer-Startzeit auf jetzt, d.h. die Zeit, zu der dieser Befehl während der Anfrage ausgeführt wird.
Die Timer-Startzeit wird standardmäßig auf die Startzeit der aktuellen Anfrage gesetzt und kann durch diese Direktive potenziell mehrfach in einem einzigen Standort überschrieben werden. Zum Beispiel:
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.";
}
Die Ausgabe auf der Client-Seite könnte sein
$ curl 'http://localhost/timed_sleep'
0.032 sec elapsed.
0.020 sec elapsed.
Die tatsächlichen Zahlen, die Sie auf Ihrer Seite erhalten, können aufgrund der aktuellen Aktivitäten Ihres Systems etwas variieren.
Der Aufruf dieser Direktive zwingt den zugrunde liegenden NGINX-Timer, auf die aktuelle Systemzeit aktualisiert zu werden (unabhängig von der Timerauflösung, die an anderer Stelle in der Konfigurationsdatei angegeben ist). Darüber hinaus werden Verweise auf die $echo_timer_elapsed-Variable ebenfalls die Timeraktualisierung zwangsweise auslösen.
Siehe auch echo_sleep und $echo_timer_elapsed.
echo_read_request_body
syntax: echo_read_request_body
default: nein
context: location, location if
phase: content
Liest den Anforderungstext ausdrücklich, sodass die $request_body-Variable immer nicht leere Werte hat (es sei denn, der Text ist so groß, dass er von NGINX in einer lokalen temporären Datei gespeichert wurde).
Beachten Sie, dass dies möglicherweise nicht der ursprüngliche Anforderungstext des Clients ist, da die aktuelle Anfrage eine Subanfrage mit einem von ihrem Elternteil angegebenen "künstlichen" Text sein könnte.
Diese Direktive erzeugt selbst keine Ausgabe, genau wie echo_sleep.
Hier ist ein Beispiel, um die ursprüngliche HTTP-Client-Anfrage zurückzugeben (sowohl Kopfzeilen als auch Text sind enthalten):
location /echoback {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo_read_request_body;
echo $request_body;
}
Der Inhalt von /echoback sieht auf meiner Seite so aus (ich habe das Perl-Tool LWP verwendet, um diesen Standort auf dem Server aufzurufen):
$ (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
Da /echoback die Hauptanfrage ist, hält $request_body den ursprünglichen Anforderungstext des Clients.
Vor NGINX 0.7.56 machte es keinen Sinn, diese Direktive zu verwenden, da $request_body erstmals in NGINX 0.7.58 eingeführt wurde.
Diese Direktive selbst wurde erstmals in der v0.14-Version des Echo-Moduls eingeführt.
echo_location_async
syntax: echo_location_async <location> [<url_args>]
default: nein
context: location, location if
phase: content
Gibt eine GET-Subanfrage an den angegebenen Standort (erstes Argument) mit optionalen URL-Argumenten im zweiten Argument aus.
Seit NGINX 0.8.20 unterstützt das location-Argument keine benannten Standorte, aufgrund einer Einschränkung in der Funktion ngx_http_subrequest. Das Gleiche gilt für seinen Bruder, die echo_location-Direktive.
Ein sehr einfaches Beispiel ist
location /main {
echo_location_async /sub;
echo world;
}
location /sub {
echo hello;
}
Der Zugriff auf /main ergibt
hello
world
Es ist auch möglich, mehrere Standorte parallel aufzurufen:
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; # schläft 2 Sekunden
echo hello;
}
location /sub2 {
echo_sleep 1; # schläft 1 Sekunde
echo world;
}
Der Zugriff auf /main ergibt
$ time curl 'http://localhost/main'
hello
world
took 0.000 sec for total.
real 0m2.006s
user 0m0.000s
sys 0m0.004s
Sie können sehen, dass der Haupt-Handler /main nicht auf die Subanfragen /sub1 und /sub2 wartet und schnell fortfährt, daher das Timing-Ergebnis "0.000 sec". Die gesamte Anfrage dauert jedoch insgesamt etwa 2 Sekunden, da /sub1 und /sub2 parallel (oder genauer gesagt "gleichzeitig") ausgeführt werden.
Wenn Sie in dem vorherigen Beispiel stattdessen echo_blocking_sleep verwenden, erhalten Sie dasselbe Ergebnis, jedoch mit einer Gesamtantwortzeit von 3 Sekunden, da "blockierender Schlaf" den gesamten NGINX-Worker-Prozess blockiert.
Standorte können auch ein optionales Querystring-Argument annehmen, zum Beispiel
location /main {
echo_location_async /sub 'foo=Foo&bar=Bar';
}
location /sub {
echo $arg_foo $arg_bar;
}
Der Zugriff auf /main ergibt
$ curl 'http://localhost/main'
Foo Bar
Querystrings dürfen nicht direkt an das location-Argument mit "?" angehängt werden, zum Beispiel ist /sub?foo=Foo&bar=Bar ein ungültiger Standort und sollte nicht als erstes Argument an diese Direktive übergeben werden.
Technisch gesehen ist diese Direktive ein Beispiel dafür, dass der NGINX-Inhalts-Handler eine oder mehrere Subanfragen direkt ausstellt. Soweit ich weiß, macht das fancyindex-Modul auch solche Dinge ;)
Benannte Standorte wie @foo werden hier nicht unterstützt.
Diese Direktive ist logisch äquivalent zur GET-Version von echo_subrequest_async. Zum Beispiel,
echo_location_async /foo 'bar=Bar';
ist logisch äquivalent zu
echo_subrequest_async GET /foo -q 'bar=Bar';
Aber das Aufrufen dieser Direktive ist etwas schneller als das Aufrufen von echo_subrequest_async mit GET, da wir die HTTP-Methodennamen wie GET und Optionen wie -q nicht parsen müssen.
Diese Direktive wurde erstmals in der Version 0.09 dieses Moduls eingeführt und erfordert mindestens NGINX 0.7.46.
echo_location
syntax: echo_location <location> [<url_args>]
default: nein
context: location, location if
phase: content
Genau wie die echo_location_async-Direktive, aber echo_location gibt Subanfragen in Serie aus, anstatt parallel. Das heißt, die nach dieser Direktive folgenden Inhalts-Handler-Direktiven werden nicht ausgeführt, bis die von dieser Direktive ausgegebene Subanfrage abgeschlossen ist.
Der endgültige Antworttext ist fast immer äquivalent zu dem Fall, wenn stattdessen echo_location_async verwendet wird, es sei denn, es werden Zeitvariablen in den Ausgaben verwendet.
Betrachten Sie das folgende Beispiel:
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;
}
Der Standort /main oben benötigt insgesamt 3 Sekunden zum Abschluss (im Vergleich zu 2 Sekunden, wenn echo_location_async stattdessen hier verwendet wird). Hier ist das Ergebnis in Aktion auf meinem Rechner:
$ curl 'http://localhost/main'
hello
world
took 3.003 sec for total.
real 0m3.027s
user 0m0.020s
sys 0m0.004s
Diese Direktive ist logisch äquivalent zur GET-Version von echo_subrequest. Zum Beispiel,
echo_location /foo 'bar=Bar';
ist logisch äquivalent zu
echo_subrequest GET /foo -q 'bar=Bar';
Aber das Aufrufen dieser Direktive ist etwas schneller als das Aufrufen von echo_subrequest mit GET, da wir die HTTP-Methodennamen wie GET und Optionen wie -q nicht parsen müssen.
Im Hintergrund erstellt sie ein ngx_http_post_subrequest_t-Objekt als Fortsetzung und übergibt es an den Aufruf der Funktion ngx_http_subrequest. NGINX wird später diese "Fortsetzung" im Funktionsaufruf ngx_http_finalize_request der Subanfrage wieder öffnen. Wir setzen die Ausführung des Inhalts-Handlers der übergeordneten Anfrage fort und beginnen, die nächste Direktive (Befehl) auszuführen, falls vorhanden.
Benannte Standorte wie @foo werden hier nicht unterstützt.
Diese Direktive wurde erstmals in der Version v0.12 eingeführt.
Siehe auch echo_location_async für weitere Details zur Bedeutung der Argumente.
echo_subrequest_async
syntax: echo_subrequest_async <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]
default: nein
context: location, location if
phase: content
Initiieren Sie eine asynchrone Subanfrage mit der HTTP-Methode, optionalen URL-Argumenten (oder Querystring) und einem optionalen Anforderungstext, der als String oder als Pfad zu einer Datei definiert werden kann, die den Text enthält.
Diese Direktive ist sehr ähnlich einer verallgemeinerten Version der echo_location_async-Direktive.
Hier ist ein kleines Beispiel, das ihre Verwendung demonstriert:
location /multi {
# body definiert als String
echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi';
# body definiert als Pfad zu einer Datei, relativ zum NGINX-Präfixpfad, wenn nicht absolut
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 '///';
}
Dann auf der Client-Seite:
$ 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
///
Hier ist ein weiteres lustiges Beispiel, das das Standard- Proxy-Modul verwendet, um die Subanfrage zu bearbeiten:
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.";
# wir müssen hier den Text ausdrücklich lesen... oder $echo_request_body
# wird leer ("") ausgewertet
echo_read_request_body;
echo "body: $echo_request_body.";
}
Dann sehen wir auf der Client-Seite, dass
$ curl 'http://localhost/main'
method: POST.
body: hello, world.
Benannte Standorte wie @foo werden hier nicht unterstützt.
Diese Direktive hat mehrere Optionen:
-q <url_args> Geben Sie die URL-Argumente (oder URL-Querystring) für die Subanfrage an.
-f <path> Geben Sie den Pfad zur Datei an, deren Inhalt als
Anforderungstext der Subanfrage dient.
-b <data> Geben Sie die Anforderungstextdaten an.
Diese Direktive wurde erstmals in der Version v0.15 eingeführt.
Die -f-Option zur Definition eines Dateipfads für den Text wurde in der Version v0.35 eingeführt.
Siehe auch die echo_subrequest und echo_location_async-Direktiven.
echo_subrequest
syntax: echo_subrequest <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]
default: nein
context: location, location if
phase: content
Dies ist die synchrone Version der echo_subrequest_async-Direktive. Und genau wie echo_location blockiert sie nicht den NGINX-Worker-Prozess (während echo_blocking_sleep dies tut), sondern verwendet stattdessen Fortsetzungen, um die Kontrolle entlang der Subanfrage-Kette zu übergeben.
Siehe echo_subrequest_async für weitere Details.
Benannte Standorte wie @foo werden hier nicht unterstützt.
Diese Direktive wurde erstmals in der Version v0.15 eingeführt.
echo_foreach_split
syntax: echo_foreach_split <delimiter> <string>
default: nein
context: location, location if
phase: content
Teilt das zweite Argument string unter Verwendung des im ersten Argument angegebenen Trennzeichens und iteriert dann durch die resultierenden Elemente. Zum Beispiel:
location /loop {
echo_foreach_split ',' $arg_list;
echo "item: $echo_it";
echo_end;
}
Der Zugriff auf /main ergibt
$ curl 'http://localhost/loop?list=cat,dog,mouse'
item: cat
item: dog
item: mouse
Wie im vorherigen Beispiel zu sehen, sollte diese Direktive immer von einer echo_end-Direktive begleitet werden.
Parallele echo_foreach_split-Schleifen sind erlaubt, aber verschachtelte sind derzeit verboten.
Das delimiter-Argument kann mehrere beliebige Zeichen enthalten, wie
# dies gibt "cat\ndog\nmouse\n" aus
echo_foreach_split -- '-a-' 'cat-a-dog-a-mouse';
echo $echo_it;
echo_end;
Logisch gesehen ist diese Schleifenstruktur einfach die foreach-Schleife kombiniert mit einem split-Funktionsaufruf in Perl (unter Verwendung des vorherigen Beispiels):
foreach (split ',', $arg_list) {
print "item $_\n";
}
Die Leute werden es auch nützlich finden, mehrere .js- oder .css-Ressourcen zu einem Ganzen zusammenzuführen. Hier ist ein Beispiel:
location /merge {
default_type 'text/javascript';
echo_foreach_split '&' $query_string;
echo "/* JS File $echo_it */";
echo_location_async $echo_it;
echo;
echo_end;
}
Dann den Zugriff auf /merge, um die im Querystring angegebenen .js-Ressourcen zusammenzuführen:
$ curl 'http://localhost/merge?/foo/bar.js&/yui/blah.js&/baz.js'
Man kann auch ein Drittanbieter-NGINX-Cache-Modul verwenden, um die durch den Standort /merge im vorherigen Beispiel generierte zusammengeführte Antwort zu cachen.
Diese Direktive wurde erstmals in der Version v0.17 eingeführt.
echo_end
syntax: echo_end
default: nein
context: location, location if
phase: content
Diese Direktive wird verwendet, um den Körper von Schleifen- und bedingten Kontrollstrukturen wie echo_foreach_split zu beenden.
Diese Direktive wurde erstmals in der Version v0.17 eingeführt.
echo_request_body
syntax: echo_request_body
default: nein
context: location, location if
phase: content
Gibt den Inhalt des zuvor gelesenen Anforderungstextes aus.
Im Hintergrund wird es grob so implementiert:
if (r->request_body && r->request_body->bufs) {
return ngx_http_output_filter(r, r->request_body->bufs);
}
Im Gegensatz zu den $echo_request_body- und $request_body-Variablen zeigt diese Direktive den gesamten Anforderungstext an, selbst wenn einige Teile oder alle Teile davon in temporären Dateien auf der Festplatte gespeichert sind.
Es ist ein "no-op", wenn noch kein Anforderungstext gelesen wurde.
Diese Direktive wurde erstmals in der Version v0.18 eingeführt.
Siehe auch echo_read_request_body und das chunkin-Modul.
echo_exec
syntax: echo_exec <location> [<query_string>]
syntax: echo_exec <named_location>
default: nein
context: location, location if
phase: content
Führt eine interne Umleitung zu dem angegebenen Standort durch. Ein optionaler Querystring kann für normale Standorte angegeben werden, wie in
location /foo {
echo_exec /bar weight=5;
}
location /bar {
echo $arg_weight;
}
Oder gleichwertig
location /foo {
echo_exec /bar?weight=5;
}
location /bar {
echo $arg_weight;
}
Benannte Standorte werden ebenfalls unterstützt. Hier ist ein Beispiel:
location /foo {
echo_exec @bar;
}
location @bar {
# Sie erhalten /foo anstelle von @bar
# aufgrund eines möglichen Fehlers in NGINX.
echo $echo_request_uri;
}
Aber der Querystring (sofern vorhanden) wird bei Umleitungen zu benannten Standorten aufgrund einer Einschränkung in der Funktion ngx_http_named_location immer ignoriert.
Versuchen Sie niemals, Dinge vor der echo_exec-Direktive auszugeben, oder Sie werden nicht die richtige Antwort des Standorts sehen, zu dem Sie umleiten möchten. Denn jede Ausgabe verursacht, dass der ursprüngliche Standort-Handler HTTP-Header sendet, bevor die Umleitung erfolgt.
Technisch gesehen exponiert diese Direktive die internen API-Funktionen von NGINX ngx_http_internal_redirect und ngx_http_named_location.
Diese Direktive wurde erstmals in der v0.21-Version eingeführt.
echo_status
syntax: echo_status <status-num>
default: echo_status 200
context: location, location if
phase: content
Gibt den Standard-Antwortstatuscode an. Standardmäßig auf 200. Diese Direktive ist deklarativ und die relative Reihenfolge zu anderen echo-ähnlichen Direktiven ist nicht wichtig.
Hier ist ein Beispiel,
location = /bad {
echo_status 404;
echo "Something is missing...";
}
dann erhalten wir eine Antwort wie diese:
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...
Diese Direktive wurde erstmals in der v0.40-Version eingeführt.
Filter-Direktiven
Die Verwendung der folgenden Direktiven löst die Filterregistrierung dieses Moduls aus. Standardmäßig wird von diesem Modul kein Filter registriert.
Jede Filter-Direktive unterstützt die Variableninterpolation in ihren Argumenten (sofern vorhanden).
echo_before_body
syntax: echo_before_body [options] [argument]...
default: nein
context: location, location if
phase: output filter
Es ist die Filterversion der echo-Direktive und fügt seine Ausgabe am Anfang der ursprünglichen Ausgaben hinzu, die vom zugrunde liegenden Inhalts-Handler generiert werden.
Ein Beispiel ist
location /echo {
echo_before_body hello;
proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more;
}
location /echo/more {
echo world
}
Der Zugriff auf /echo von der Client-Seite ergibt
hello
world
Im vorherigen Beispiel verwenden wir das Standard-Proxy-Modul als zugrunde liegenden Inhalts-Handler, der die "Hauptinhalte" generiert.
Mehrere Instanzen dieser Filter-Direktive sind ebenfalls erlaubt, wie in:
location /echo {
echo_before_body hello;
echo_before_body world;
echo !;
}
Auf der Client-Seite sieht die Ausgabe so aus
$ curl 'http://localhost/echo'
hello
world
!
In diesem Beispiel verwenden wir auch die von diesem Modul bereitgestellten Inhalts-Handler-Direktiven als zugrunde liegenden Inhalts-Handler.
Diese Direktive unterstützt auch die -n- und ---Optionen wie die echo-Direktive.
Diese Direktive kann mit ihrer Schwester-Direktive echo_after_body gemischt werden.
echo_after_body
syntax: echo_after_body [argument]...
default: nein
context: location, location if
phase: output filter
Es ist sehr ähnlich der echo_before_body-Direktive, aber fügt seine Ausgabe am Ende der ursprünglichen Ausgaben hinzu, die vom zugrunde liegenden Inhalts-Handler generiert werden.
Hier ist ein einfaches Beispiel:
location /echo {
echo_after_body hello;
proxy_pass http://127.0.0.1:$server_port$request_uri/more;
}
location /echo/more {
echo world
}
Der Zugriff auf /echo von der Client-Seite ergibt
world
hello
Mehrere Instanzen sind erlaubt, wie in:
location /echo {
echo_after_body hello;
echo_after_body world;
echo i;
echo say;
}
Die Ausgabe auf der Client-Seite beim Zugriff auf den Standort /echo sieht aus wie
i
say
hello
world
Diese Direktive unterstützt auch die -n- und ---Optionen wie die echo-Direktive.
Diese Direktive kann mit ihrer Schwester-Direktive echo_before_body gemischt werden.
Variablen
$echo_it
Dies ist eine "Themenvariable", die von echo_foreach_split verwendet wird, genau wie die $_-Variable in Perl.
$echo_timer_elapsed
Diese Variable hält die seit Beginn der aktuellen Anfrage (kann eine Subanfrage sein) oder der letzten Ausführung des echo_reset_timer-Befehls verstrichenen Sekunden.
Das Timing-Ergebnis hat drei Ziffern nach dem Dezimalpunkt.
Verweise auf diese Variable zwingen den zugrunde liegenden NGINX-Timer, auf die aktuelle Systemzeit zu aktualisieren, unabhängig von den Timerauflösungseinstellungen an anderer Stelle in der Konfigurationsdatei, genau wie die echo_reset_timer-Direktive.
$echo_request_body
Wird auf den aktuellen (Sub)Anforderungstext ausgewertet, der zuvor gelesen wurde, wenn kein Teil des Textes in einer temporären Datei gespeichert wurde. Um den Anforderungstext immer anzuzeigen, selbst wenn er sehr groß ist, verwenden Sie die echo_request_body-Direktive.
$echo_request_method
Wird auf die HTTP-Anforderungsmethode der aktuellen Anfrage ausgewertet (es kann eine Subanfrage sein).
Im Hintergrund nimmt es einfach die Zeichenfolgendaten, die in r->method_name gespeichert sind.
Vergleichen Sie es mit der $echo_client_request_method-Variable.
Mindestens für NGINX 0.8.20 und älter tut die $request_method-Variable, die vom HTTP-Kernmodul bereitgestellt wird, tatsächlich das, was unsere $echo_client_request_method tut.
Diese Variable wurde erstmals in unserer v0.15-Version eingeführt.
$echo_client_request_method
Wird immer auf die HTTP-Methode der Hauptanfrage ausgewertet, selbst wenn die aktuelle Anfrage eine Subanfrage ist.
Im Hintergrund nimmt es einfach die Zeichenfolgendaten, die in r->main->method_name gespeichert sind.
Vergleichen Sie es mit der $echo_request_method-Variable.
Diese Variable wurde erstmals in unserer v0.15-Version eingeführt.
$echo_client_request_headers
Wird auf die Header der ursprünglichen Client-Anfrage ausgewertet.
Wie der Name schon sagt, wird es immer auf die Hauptanfrage (oder die Client-Anfrage) ausgewertet, selbst wenn es derzeit in einer Subanfrage ausgeführt wird.
Ein einfaches Beispiel ist unten:
location /echoback {
echo "headers are:"
echo $echo_client_request_headers;
}
Der Zugriff auf /echoback ergibt
$ 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: */*
Im Hintergrund wird r->main->header_in (oder die großen Header-Puffer, falls vorhanden) auf C-Ebene wiederhergestellt und die Header werden nicht selbst konstruiert, indem die analysierten Ergebnisse im Anfrageobjekt durchlaufen werden.
Diese Variable wird derzeit immer auf einen leeren Wert in HTTP/2-Anfragen ausgewertet, aufgrund der aktuellen Implementierung.
Diese Variable wurde erstmals in der Version 0.15 eingeführt.
$echo_cacheable_request_uri
Wird auf die geparste Form der URI (normalerweise mit / beginnend) der aktuellen (Sub-)Anfrage ausgewertet. Im Gegensatz zur $echo_request_uri-Variable ist sie cachebar.
Siehe $echo_request_uri für weitere Details.
Diese Variable wurde erstmals in der Version 0.17 eingeführt.
$echo_request_uri
Wird auf die geparste Form der URI (normalerweise mit / beginnend) der aktuellen (Sub-)Anfrage ausgewertet. Im Gegensatz zur $echo_cacheable_request_uri-Variable ist sie nicht cachebar.
Dies unterscheidet sich erheblich von der $request_uri-Variable, die vom ngx_http_core_module exportiert wird, da $request_uri die unparste Form der URI der aktuellen Anfrage ist.
Diese Variable wurde erstmals in der Version 0.17 eingeführt.
$echo_incr
Es ist ein Zähler, der immer die aktuelle Zählnummer generiert, beginnend bei 1. Der Zähler ist immer mit der Hauptanfrage verbunden, selbst wenn er innerhalb einer Subanfrage aufgerufen wird.
Betrachten Sie das folgende Beispiel
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";
}
Der Zugriff auf /main ergibt
main pre: 1
sub: 3
sub: 4
main post: 2
Diese Direktive wurde erstmals in der v0.18-Version eingeführt.
$echo_response_status
Wird auf den Statuscode der aktuellen (Sub)Anfrage ausgewertet, null, wenn keiner vorhanden ist.
Im Hintergrund ist es einfach die textuelle Darstellung von r->headers_out->status.
Diese Direktive wurde erstmals in der v0.23-Version eingeführt.
Module, die dieses Modul für Tests verwenden
Die folgenden Module nutzen dieses echo-Modul in ihrer Test-Suite:
- Das memc-Modul, das fast das gesamte memcached TCP-Protokoll unterstützt.
- Das chunkin-Modul, das HTTP 1.1 Chunked-Eingabunterstützung zu NGINX hinzufügt.
- Das headers_more-Modul, das es Ihnen ermöglicht, Eingabe- und Ausgabekopfzeilen unter den von Ihnen festgelegten Bedingungen hinzuzufügen, festzulegen und zu löschen.
- Das
echo-Modul selbst.
Bitte mailen Sie mir andere Module, die echo in irgendeiner Form verwenden, und ich werde sie zur obigen Liste hinzufügen :)
Änderungen
Die Änderungen jeder Version dieses Moduls können aus den Änderungsprotokollen des OpenResty-Bundles abgerufen werden:
Test-Suite
Dieses Modul wird mit einer Perl-gesteuerten Test-Suite geliefert. Die Testfälle sind ebenfalls deklarativ. Dank des Test::Nginx-Moduls in der Perl-Welt.
Um es auf Ihrer Seite auszuführen:
$ PATH=/path/to/your/nginx-with-echo-module:$PATH prove -r t
Sie müssen alle NGINX-Prozesse beenden, bevor Sie die Test-Suite ausführen, wenn Sie die NGINX-Server-Binärdatei geändert haben.
Da ein einzelner NGINX-Server (standardmäßig localhost:1984) in allen Testskripten (.t-Dateien) verwendet wird, ist es sinnlos, die Test-Suite parallel auszuführen, indem Sie -jN beim Aufruf des prove-Dienstprogramms angeben.
Einige Teile der Test-Suite erfordern auch, dass die Standardmodule proxy, rewrite und SSI aktiviert sind, wenn NGINX gebaut wird.
Siehe auch
- Der ursprüngliche Blogbeitrag über die anfängliche Entwicklung dieses Moduls.
- Das Standard-Addition-Filtermodul.
- Das Standard-Proxy-Modul.
- Das OpenResty-Bundle.
GitHub
Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-echo.