http: Lua HTTP-Client-Cosocket-Treiber für nginx-module-lua
Installation
Wenn Sie das RPM-Repository-Abonnement nicht eingerichtet haben, melden Sie sich an. Dann können Sie mit den folgenden Schritten fortfahren.
CentOS/RHEL 7 oder Amazon Linux 2
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 lua-resty-http
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-http
Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.
Dieses Dokument beschreibt lua-resty-http v0.17.2, veröffentlicht am 29. Februar 2024.
Lua HTTP-Client-Cosocket-Treiber für OpenResty / ngx_lua.
Funktionen
- HTTP 1.0 und 1.1
- SSL
- Streaming-Schnittstelle zum Antwortkörper, für vorhersehbaren Speicherverbrauch
- Alternative einfache Schnittstelle für Einmalanfragen ohne manuellen Verbindungsschritt
- Chunked und nicht-chunked Übertragungsencodierungen
- Verbindungskeepalives
- Anfrage-Pipelining
- Trailer
- HTTP-Proxy-Verbindungen
- mTLS (erfordert
ngx_lua_http_module>= v0.10.23)
API
- new
- connect
- set_proxy_options
- set_timeout
- set_timeouts
- set_keepalive
- get_reused_times
- close
- request
- request_uri
- request_pipeline
- parse_uri
- get_client_body_reader
- Response
Abgelehnt
Diese Methoden können in zukünftigen Versionen entfernt werden.
Verwendung
Es gibt zwei grundlegende Betriebsmodi:
-
Einfache Einmalanfragen, die kein manuelles Verbindungsmanagement erfordern, aber die gesamte Antwort puffern und die Verbindung entweder geschlossen oder zurück im Verbindungs-Pool lassen.
-
Gestreamte Anfragen, bei denen die Verbindung separat hergestellt wird, dann die Anfrage gesendet wird, der Körperstream in Chunks gelesen wird und schließlich die Verbindung manuell geschlossen oder aktiv gehalten wird. Diese Technik erfordert etwas mehr Code, bietet jedoch die Möglichkeit, potenziell große Antwortkörper auf der Lua-Seite zu verwerfen sowie mehrere Anfragen über eine einzige Verbindung zu pipelinen.
Einmalanfrage
local httpc = require("resty.http").new()
-- Einmalanfragen verwenden die `request_uri`-Schnittstelle.
local res, err = httpc:request_uri("http://example.com/helloworld", {
method = "POST",
body = "a=1&b=2",
headers = {
["Content-Type"] = "application/x-www-form-urlencoded",
},
})
if not res then
ngx.log(ngx.ERR, "Anfrage fehlgeschlagen: ", err)
return
end
-- An diesem Punkt ist die gesamte Anfrage / Antwort abgeschlossen und die Verbindung
-- wird geschlossen oder zurück im Verbindungs-Pool sein.
-- Die `res`-Tabelle enthält die erwarteten Felder `status`, `headers` und `body`.
local status = res.status
local length = res.headers["Content-Length"]
local body = res.body
Gestreamte Anfrage
local httpc = require("resty.http").new()
-- Zuerst eine Verbindung herstellen
local ok, err, ssl_session = httpc:connect({
scheme = "https",
host = "127.0.0.1",
port = 8080,
})
if not ok then
ngx.log(ngx.ERR, "Verbindung fehlgeschlagen: ", err)
return
end
-- Dann mit `request` senden, indem ein Pfad und der `Host`-Header anstelle eines
-- vollständigen URI bereitgestellt werden.
local res, err = httpc:request({
path = "/helloworld",
headers = {
["Host"] = "example.com",
},
})
if not res then
ngx.log(ngx.ERR, "Anfrage fehlgeschlagen: ", err)
return
end
-- An diesem Punkt werden der Status und die Header in der `res`
-- Tabelle verfügbar sein, aber der Körper und alle Trailer werden noch auf der Leitung sein.
-- Wir können den `body_reader`-Iterator verwenden, um den Körper gemäß unserer
-- gewünschten Puffergröße zu streamen.
local reader = res.body_reader
local buffer_size = 8192
repeat
local buffer, err = reader(buffer_size)
if err then
ngx.log(ngx.ERR, err)
break
end
if buffer then
-- verarbeiten
end
until not buffer
local ok, err = httpc:set_keepalive()
if not ok then
ngx.say("Fehler beim Setzen von Keepalive: ", err)
return
end
-- An diesem Punkt wird die Verbindung entweder sicher im Pool sein oder geschlossen.
````
## Verbindung
## new
`syntax: httpc, err = http.new()`
Erstellt das HTTP-Verbindungsobjekt. Im Falle von Fehlern gibt es `nil` und eine Zeichenfolge zurück, die den Fehler beschreibt.
## connect
`syntax: ok, err, ssl_session = httpc:connect(options)`
Versucht, eine Verbindung zum Webserver herzustellen und dabei die folgenden Aktivitäten zu integrieren:
- TCP-Verbindung
- SSL-Handshake
- HTTP-Proxy-Konfiguration
Dabei wird ein distinct connection pool name erstellt, der sicher mit SSL und/oder Proxy-basierten Verbindungen verwendet werden kann. Diese Syntax wird daher dringend empfohlen gegenüber der ursprünglichen (jetzt abgelehnten) [TCP-Only-Verbindungssyntax](#TCP-only-connect).
Die Optionen-Tabelle hat die folgenden Felder:
* `scheme`: zu verwendendes Schema oder nil für Unix-Domain-Socket
* `host`: Zielhost oder Pfad zu einem Unix-Domain-Socket
* `port`: Port am Zielhost, standardmäßig `80` oder `443`, je nach Schema
* `pool`: benutzerdefinierter Verbindungs-Poolname. Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsockconnect), außer dass der Standard ein Poolname wird, der unter Verwendung der SSL-/Proxy-Eigenschaften konstruiert wird, was wichtig für eine sichere Wiederverwendung der Verbindung ist. Im Zweifelsfall leer lassen!
* `pool_size`: Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsockconnect)
* `backlog`: Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsockconnect)
* `proxy_opts`: Untertabelle, standardmäßig auf die globalen Proxy-Optionen gesetzt, siehe [set\_proxy\_options](#set_proxy_options).
* `ssl_reused_session`: Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)
* `ssl_verify`: Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake), außer dass sie standardmäßig auf `true` gesetzt ist.
* `ssl_server_name`: Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)
* `ssl_send_status_req`: Option gemäß [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)
* `ssl_client_cert`: wird an `tcpsock:setclientcert` übergeben. Erfordert `ngx_lua_http_module` >= v0.10.23.
* `ssl_client_priv_key`: wie oben.
## set\_timeout
`syntax: httpc:set_timeout(time)`
Setzt das Socket-Timeout (in ms) für nachfolgende Operationen. Siehe [set\_timeouts](#set_timeouts) unten für einen deklarativeren Ansatz.
## set\_timeouts
`syntax: httpc:set_timeouts(connect_timeout, send_timeout, read_timeout)`
Setzt die Verbindungs-Timeout-Schwelle, die Sendetimeout-Schwelle und die Lese-Timeout-Schwelle in Millisekunden für nachfolgende Socket-Operationen (verbinden, senden, empfangen und Iteratoren, die von receiveuntil zurückgegeben werden).
## set\_keepalive
`syntax: ok, err = httpc:set_keepalive(max_idle_timeout, pool_size)`
Entweder wird die aktuelle Verbindung in den Pool für zukünftige Wiederverwendung gelegt oder die Verbindung wird geschlossen. Dies anstelle von [close](#close) aufzurufen, ist "sicher", da es bedingt schließt, je nach Art der Anfrage. Insbesondere wird eine `1.0`-Anfrage ohne `Connection: Keep-Alive` geschlossen, ebenso wie eine `1.1`-Anfrage mit `Connection: Close`.
Im Erfolgsfall gibt es `1` zurück. Im Fehlerfall gibt es `nil, err` zurück. Im Fall, dass die Verbindung bedingt geschlossen wird, wie oben beschrieben, gibt es `2` und die Fehlermeldung `connection must be closed` zurück, um sie von unerwarteten Fehlern zu unterscheiden.
Siehe [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsocksetkeepalive) für die Parameterdokumentation.
## set\_proxy\_options
`syntax: httpc:set_proxy_options(opts)`
Konfiguriert einen HTTP-Proxy, der mit dieser Client-Instanz verwendet werden soll. Die `opts`-Tabelle erwartet die folgenden Felder:
* `http_proxy`: eine URI zu einem Proxy-Server, der für HTTP-Anfragen verwendet werden soll
* `http_proxy_authorization`: ein Standardwert für den `Proxy-Authorization`-Header, der mit `http_proxy` verwendet werden soll, z.B. `Basic ZGVtbzp0ZXN0`, der überschrieben wird, wenn der `Proxy-Authorization`-Anforderungsheader vorhanden ist.
* `https_proxy`: eine URI zu einem Proxy-Server, der für HTTPS-Anfragen verwendet werden soll
* `https_proxy_authorization`: wie `http_proxy_authorization`, aber für die Verwendung mit `https_proxy` (da bei HTTPS die Autorisierung beim Verbinden erfolgt, kann dieser nicht durch Übergeben des `Proxy-Authorization`-Anforderungsheaders überschrieben werden).
* `no_proxy`: eine durch Kommas getrennte Liste von Hosts, die nicht über einen Proxy geleitet werden sollen.
Beachten Sie, dass diese Methode keine Auswirkungen hat, wenn die abgelehnte [TCP-Only-Verbindung](#TCP-only-connect) verwendet wird.
## get\_reused\_times
`syntax: times, err = httpc:get_reused_times()`
Siehe [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsockgetreusedtimes).
## close
`syntax: ok, err = httpc:close()`
Siehe [OpenResty-Dokumentation](https://github.com/openresty/lua-nginx-module#tcpsockclose).
## Anfragen
## request
`syntax: res, err = httpc:request(params)`
Sendet eine HTTP-Anfrage über eine bereits etablierte Verbindung. Gibt eine `res`-Tabelle oder `nil` und eine Fehlermeldung zurück.
Die `params`-Tabelle erwartet die folgenden Felder:
* `version`: Die HTTP-Version. Standardmäßig `1.1`.
* `method`: Die HTTP-Methode als Zeichenfolge. Standardmäßig `GET`.
* `path`: Die Pfadzeichenfolge. Standardmäßig `/`.
* `query`: Die Abfragezeichenfolge, entweder als literale Zeichenfolge oder als Lua-Tabelle.
* `headers`: Eine Tabelle der Anforderungsheader.
* `body`: Der Anfragekörper als Zeichenfolge, eine Tabelle von Zeichenfolgen oder eine Iteratorfunktion, die Zeichenfolgen bis nil zurückgibt, wenn sie erschöpft ist. Beachten Sie, dass Sie eine `Content-Length` für den Anfragekörper angeben müssen oder `Transfer-Encoding: chunked` angeben und Ihre Funktion die Codierung implementieren muss. Siehe auch: [get\_client\_body\_reader](#get_client_body_reader).
Wenn die Anfrage erfolgreich ist, enthält `res` die folgenden Felder:
* `status`: Der Statuscode.
* `reason`: Der Statusgrundsatz.
* `headers`: Eine Tabelle von Headern. Mehrere Header mit demselben Feldnamen werden als Tabelle von Werten präsentiert.
* `has_body`: Ein boolesches Flag, das angibt, ob ein Körper gelesen werden kann.
* `body_reader`: Eine Iteratorfunktion zum Streaming des Körpers.
* `read_body`: Eine Methode, um den gesamten Körper in eine Zeichenfolge zu lesen.
* `read_trailers`: Eine Methode, um alle Trailer unter den Headern zu verbinden, nachdem der Körper gelesen wurde.
Wenn die Antwort einen Körper hat, müssen Sie diesen mit `read_body` oder `body_reader` lesen, bevor dieselbe Verbindung für eine andere Anfrage verwendet werden kann.
## request\_uri
`syntax: res, err = httpc:request_uri(uri, params)`
Die Einmalanfrageschnittstelle (siehe [Verwendung](#Verwendung)). Da diese Methode eine vollständige End-to-End-Anfrage durchführt, können die in `params` angegebenen Optionen alles enthalten, was sowohl in [connect](#connect) als auch in [request](#request) oben dokumentiert ist. Beachten Sie auch, dass die Felder `path` und `query` in `params` relevante Komponenten des `uri` überschreiben, wenn sie angegeben sind (`scheme`, `host` und `port` werden immer aus dem `uri` entnommen).
Es gibt 3 zusätzliche Parameter zur Steuerung von Keepalives:
* `keepalive`: Auf `false` setzen, um Keepalives zu deaktivieren und die Verbindung sofort zu schließen. Standardmäßig `true`.
* `keepalive_timeout`: Die maximale Leerlaufzeit (ms). Standardmäßig `lua_socket_keepalive_timeout`.
* `keepalive_pool`: Die maximale Anzahl von Verbindungen im Pool. Standardmäßig `lua_socket_pool_size`.
Wenn die Anfrage erfolgreich ist, enthält `res` die folgenden Felder:
* `status`: Der Statuscode.
* `headers`: Eine Tabelle von Headern.
* `body`: Der gesamte Antwortkörper als Zeichenfolge.
## request\_pipeline
`syntax: responses, err = httpc:request_pipeline(params)`
Diese Methode funktioniert wie die oben beschriebene [request](#request)-Methode, aber `params` ist stattdessen eine verschachtelte Tabelle von Parameter-Tabellen. Jede Anfrage wird der Reihe nach gesendet, und `responses` wird als Tabelle von Antworthandles zurückgegeben. Zum Beispiel:
```lua
local responses = httpc:request_pipeline({
{ path = "/b" },
{ path = "/c" },
{ path = "/d" },
})
for _, r in ipairs(responses) do
if not r.status then
ngx.log(ngx.ERR, "Socket-Lese-Fehler")
break
end
ngx.say(r.status)
ngx.say(r:read_body())
end
Aufgrund der Natur des Pipelining werden keine Antworten tatsächlich gelesen, bis Sie versuchen, die Antwortfelder (Status / Header usw.) zu verwenden. Und da die Antworten der Reihe nach gelesen werden, müssen Sie den gesamten Körper (und alle Trailer, wenn Sie welche haben) lesen, bevor Sie versuchen, die nächste Antwort zu lesen.
Beachten Sie, dass dies die Verwendung des Streaming-Antwortkörperlesers nicht ausschließt. Antworten können weiterhin gestreamt werden, solange der gesamte Körper gestreamt wird, bevor Sie versuchen, auf die nächste Antwort zuzugreifen.
Stellen Sie sicher, dass Sie mindestens ein Feld (wie den Status) testen, bevor Sie versuchen, die anderen zu verwenden, falls ein Socket-Lese-Fehler aufgetreten ist.
Antwort
res.body_reader
Der body_reader-Iterator kann verwendet werden, um den Antwortkörper in von Ihnen gewählten Chunkgrößen zu streamen, wie folgt:
local reader = res.body_reader
local buffer_size = 8192
repeat
local buffer, err = reader(buffer_size)
if err then
ngx.log(ngx.ERR, err)
break
end
if buffer then
-- verarbeiten
end
until not buffer
Wenn der Reader ohne Argumente aufgerufen wird, hängt das Verhalten vom Typ der Verbindung ab. Wenn die Antwort als chunked codiert ist, gibt der Iterator die Chunks zurück, sobald sie ankommen. Andernfalls gibt er einfach den gesamten Körper zurück.
Beachten Sie, dass die angegebene Größe tatsächlich eine maximale Größe ist. Im Fall der chunked Übertragung können Sie Puffer erhalten, die kleiner sind als die angegebene Größe, als Rest der tatsächlich codierten Chunks.
res:read_body
syntax: body, err = res:read_body()
Liest den gesamten Körper in eine lokale Zeichenfolge.
res:read_trailers
syntax: res:read_trailers()
Dies verbindet alle Trailer unter der res.headers-Tabelle selbst. Muss nach dem Lesen des Körpers aufgerufen werden.
Dienstprogramm
parse_uri
syntax: local scheme, host, port, path, query? = unpack(httpc:parse_uri(uri, query_in_path?))
Dies ist eine Hilfsfunktion, die es einfacher macht, die generische Schnittstelle zu verwenden, wenn die Eingabedaten eine URI sind.
Seit Version 0.10 wurde der optionale Parameter query_in_path hinzugefügt, der angibt, ob die Abfragezeichenfolge im Rückgabewert path enthalten sein soll oder separat als eigener Rückgabewert. Dies ist standardmäßig auf true gesetzt, um die Abwärtskompatibilität zu wahren. Wenn auf false gesetzt, enthält path nur den Pfad, und query enthält die URI-Argumente, ohne das ?-Trennzeichen.
get_client_body_reader
syntax: reader, err = httpc:get_client_body_reader(chunksize?, sock?)
Gibt eine Iteratorfunktion zurück, die verwendet werden kann, um den downstream-Client-Anfragekörper in einem Streaming-Stil zu lesen. Sie können auch eine optionale Standard-Chunksize (Standard ist 65536) oder einen bereits etablierten Socket anstelle der Client-Anfrage angeben.
Beispiel:
local req_reader = httpc:get_client_body_reader()
local buffer_size = 8192
repeat
local buffer, err = req_reader(buffer_size)
if err then
ngx.log(ngx.ERR, err)
break
end
if buffer then
-- verarbeiten
end
until not buffer
Dieser Iterator kann auch als Wert für das body-Feld in den Anfrageparametern verwendet werden, sodass man den Anfragekörper in eine proxied upstream-Anfrage streamen kann.
local client_body_reader, err = httpc:get_client_body_reader()
local res, err = httpc:request({
path = "/helloworld",
body = client_body_reader,
})
Abgelehnt
Diese Funktionen bleiben aus Gründen der Abwärtskompatibilität bestehen, können jedoch in zukünftigen Versionen entfernt werden.
TCP-Only-Verbindung
Die folgenden Versionen der connect-Methodensignatur sind zugunsten des einzelnen table-Arguments oben dokumentiert abgelehnt worden.
syntax: ok, err = httpc:connect(host, port, options_table?)
syntax: ok, err = httpc:connect("unix:/path/to/unix.sock", options_table?)
HINWEIS: Der Standard-Poolname wird nur IP- und Portinformationen enthalten, sodass er bei SSL- und/oder Proxy-Verbindungen unsicher ist. Geben Sie Ihren eigenen Pool an oder verwenden Sie besser diese Signaturen nicht.
connect_proxy
syntax: ok, err = httpc:connect_proxy(proxy_uri, scheme, host, port, proxy_authorization)
Das manuelle Aufrufen dieser Methode ist nicht mehr erforderlich, da sie in connect integriert ist. Sie wird vorerst zur Kompatibilität mit Benutzern der älteren TCP-Only-Verbindung beibehalten.
Versucht, eine Verbindung zum Webserver über den angegebenen Proxy-Server herzustellen. Die Methode akzeptiert die folgenden Argumente:
proxy_uri- Vollständige URI des zu verwendenden Proxy-Servers (z.B.http://proxy.example.com:3128/). Hinweis: Nur dashttp-Protokoll wird unterstützt.scheme- Das Protokoll, das zwischen dem Proxy-Server und dem Remote-Host verwendet werden soll (httpoderhttps). Wennhttpsals Schema angegeben ist, führtconnect_proxy()eineCONNECT-Anfrage aus, um einen TCP-Tunnel zum Remote-Host über den Proxy-Server herzustellen.host- Der Hostname des Remote-Hosts, zu dem eine Verbindung hergestellt werden soll.port- Der Port des Remote-Hosts, zu dem eine Verbindung hergestellt werden soll.proxy_authorization- DerProxy-Authorization-Headerwert, der überCONNECTan den Proxy-Server gesendet wird, wenn dasschemehttpsist.
Wenn während des Verbindungsversuchs ein Fehler auftritt, gibt diese Methode nil mit einer Zeichenfolge zurück, die den Fehler beschreibt. Wenn die Verbindung erfolgreich hergestellt wurde, gibt die Methode 1 zurück.
Es gibt einige wichtige Punkte zu beachten, wenn Sie diese API verwenden:
- Wenn das Schema
httpsist, müssen Sie das TLS-Handshake manuell mit dem Remote-Server unter Verwendung der Methodessl_handshake()durchführen, bevor Sie Anfragen über den Proxy-Tunnel senden. - Wenn das Schema
httpist, müssen Sie sicherstellen, dass die Anfragen, die Sie über die Verbindungen senden, RFC 7230 und insbesondere Abschnitt 5.3.2. entsprechen, der besagt, dass das Anfrageziel in absoluter Form vorliegen muss. In der Praxis bedeutet dies, dass, wenn Siesend_request()verwenden, derpatheine absolute URI zur Ressource sein muss (z.B.http://example.com/index.htmlanstelle von nur/index.html).
ssl_handshake
syntax: session, err = httpc:ssl_handshake(session, host, verify)
Das manuelle Aufrufen dieser Methode ist nicht mehr erforderlich, da sie in connect integriert ist. Sie wird vorerst zur Kompatibilität mit Benutzern der älteren TCP-Only-Verbindung beibehalten.
Siehe OpenResty-Dokumentation.
proxy_request / proxy_response
Diese beiden Hilfsmethoden sollten lediglich einen häufigen Anwendungsfall der Implementierung von Reverse-Proxying demonstrieren, und der Autor bedauert ihre Aufnahme in das Modul. Benutzer werden ermutigt, ihre eigenen Lösungen zu entwickeln, anstatt von diesen Funktionen abhängig zu sein, die in einer späteren Version entfernt werden könnten.
proxy_request
syntax: local res, err = httpc:proxy_request(request_body_chunk_size?)
Führt eine Anfrage mit den aktuellen Client-Anfrageargumenten durch und proxyed effektiv zur verbundenen Upstream. Der Anfragekörper wird in einem Streaming-Stil gemäß request_body_chunk_size gelesen (siehe Dokumentation zum Client-Körperleser unten).
proxy_response
syntax: httpc:proxy_response(res, chunksize?)
Setzt die aktuelle Antwort basierend auf dem gegebenen res. Stellt sicher, dass hop-by-hop-Header nicht downstream gesendet werden, und liest die Antwort gemäß chunksize (siehe Dokumentation zum Körperleser oben).
GitHub
Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-http.