Zum Inhalt

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

  1. statische Inhalte direkt aus dem Speicher bereitstellen müssen (Laden aus der NGINX-Konfigurationsdatei).
  2. 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).
  3. 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:

  1. Parallel Subanfragen direkt vom Inhalts-Handler ausstellen.
  2. Verkettete Subanfragen direkt vom Inhalts-Handler ausstellen, indem die Fortsetzung entlang der Subanfrage-Kette übergeben wird.
  3. Subanfragen mit allen HTTP 1.1-Methoden und sogar einem optionalen gefälschten HTTP-Anforderungstext ausstellen.
  4. 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.
  5. Dual-Rollen-Modul, das (faul) als Inhalts-Handler oder Ausgabefilter oder beides dienen kann.
  6. Erstellung und Interpolation von NGINX-Konfigurationsdatei-Variablen.
  7. Streaming-Ausgabesteuerung mit output_chain, flush und seinen Freunden.
  8. Den Anforderungstext des Clients vom Inhalts-Handler lesen und (asynchron) an den Inhalts-Handler zurückgeben, nachdem die Verarbeitung abgeschlossen ist.
  9. 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:

http://openresty.org/#Changes

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

GitHub

Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-echo.