httpipe: Lua HTTP-Client-Cosocket-Treiber für nginx-module-lua, Schnittstellen sind flexibler
Installation
Wenn Sie das RPM-Repository-Abonnement noch 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-httpipe
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-httpipe
Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.
Dieses Dokument beschreibt lua-resty-httpipe v0.5, veröffentlicht am 25. November 2015.
Lua HTTP-Client-Cosocket-Treiber für OpenResty / ngx_lua.
Funktionen
- HTTP 1.0/1.1 und HTTPS
- Flexibles Schnittstellendesign
- Streaming-Leser und Uploads
- Chunked-encoding Anfrage-/Antwortkörper
- Setzt das Timeout für Lese- und Sendeoperationen
- Begrenzung der maximalen Antwortkörpergröße
- Keepalive
Zusammenfassung
server {
listen 9090;
location /echo {
content_by_lua '
local raw_header = ngx.req.raw_header()
if ngx.req.get_method() == "GET" then
ngx.header["Content-Length"] = #raw_header
end
ngx.req.read_body()
local body, err = ngx.req.get_body_data()
ngx.print(raw_header)
ngx.print(body)
';
}
location /simple {
content_by_lua '
local httpipe = require "resty.httpipe"
local hp, err = httpipe:new()
if not hp then
ngx.log(ngx.ERR, "failed to new httpipe: ", err)
return ngx.exit(503)
end
hp:set_timeout(5 * 1000) -- 5 sec
local res, err = hp:request("127.0.0.1", 9090, {
method = "GET", path = "/echo" })
if not res then
ngx.log(ngx.ERR, "failed to request: ", err)
return ngx.exit(503)
end
ngx.status = res.status
for k, v in pairs(res.headers) do
ngx.header[k] = v
end
ngx.say(res.body)
';
}
location /generic {
content_by_lua '
local cjson = require "cjson"
local httpipe = require "resty.httpipe"
local hp, err = httpipe:new(10) -- chunk_size = 10
if not hp then
ngx.log(ngx.ERR, "failed to new httpipe: ", err)
return ngx.exit(503)
end
hp:set_timeout(5 * 1000) -- 5 sec
local ok, err = hp:connect("127.0.0.1", 9090)
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err)
return ngx.exit(503)
end
local ok, err = hp:send_request{ method = "GET", path = "/echo" }
if not ok then
ngx.log(ngx.ERR, "failed to send request: ", err)
return ngx.exit(503)
end
-- vollständiger Streaming-Parser
while true do
local typ, res, err = hp:read()
if not typ then
ngx.say("failed to read: ", err)
return
end
ngx.say("read: ", cjson.encode({typ, res}))
if typ == 'eof' then
break
end
end
';
}
location /advanced {
content_by_lua '
local httpipe = require "resty.httpipe"
local hp, err = httpipe:new()
hp:set_timeout(5 * 1000) -- 5 sec
local r0, err = hp:request("127.0.0.1", 9090, {
method = "GET", path = "/echo",
stream = true })
-- von einem HTTP-Stream zu einem anderen, wie eine Unix-Pipe
local pipe = r0.pipe
pipe:set_timeout(5 * 1000) -- 5 sec
--[[
local headers = {["Content-Length"] = r0.headers["Content-Length"]}
local r1, err = pipe:request("127.0.0.1", 9090, {
method = "POST", path = "/echo",
headers = headers,
body = r0.body_reader })
--]]
local r1, err = pipe:request("127.0.0.1", 9090, {
method = "POST", path = "/echo" })
ngx.status = r1.status
for k, v in pairs(r1.headers) do
ngx.header[k] = v
end
ngx.say(r1.body)
';
}
}
Eine typische Ausgabe der oben definierten /simple-Location ist:
GET /echo HTTP/1.1
Host: 127.0.0.1
User-Agent: Resty/HTTPipe-1.00
Accept: */*
Eine typische Ausgabe der oben definierten /generic-Location ist:
read: ["statusline","200"]
read: ["header",["Server","openresty\/1.5.12.1","Server: openresty\/1.5.12.1"]]
read: ["header",["Date","Tue, 10 Jun 2014 07:29:57 GMT","Date: Tue, 10 Jun 2014 07:29:57 GMT"]]
read: ["header",["Content-Type","text\/plain","Content-Type: text\/plain"]]
read: ["header",["Connection","keep-alive","Connection: keep-alive"]]
read: ["header",["Content-Length","84","Content-Length: 84"]]
read: ["header_end"]
read: ["body","GET \/echo "]
read: ["body","HTTP\/1.1\r\n"]
read: ["body","Host: 127."]
read: ["body","0.0.1\r\nUse"]
read: ["body","r-Agent: R"]
read: ["body","esty\/HTTPi"]
read: ["body","pe-1.00\r\nA"]
read: ["body","ccept: *\/*"]
read: ["body","\r\n\r\n"]
read: ["body_end"]
read: ["eof"]
Eine typische Ausgabe der oben definierten /advanced-Location ist:
POST /echo HTTP/1.1
Content-Length: 84
User-Agent: Resty/HTTPipe-1.00
Accept: */*
Host: 127.0.0.1
GET /echo HTTP/1.1
Host: 127.0.0.1
User-Agent: Resty/HTTPipe-1.00
Accept: */*
Verbindung
new
syntax: hp, err = httpipe:new(chunk_size?, sock?)
Erstellt das httpipe-Objekt. Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Das Argument chunk_size gibt die Puffergröße an, die von Cosocket-Leseoperationen verwendet wird. Standardmäßig 8192.
connect
syntax: ok, err = hp:connect(host, port, options_table?)
syntax: ok, err = hp:connect("unix:/path/to/unix.sock", options_table?)
Versucht, eine Verbindung zum Webserver herzustellen.
Bevor der Hostname tatsächlich aufgelöst und eine Verbindung zum Remote-Backend hergestellt wird, sucht diese Methode immer im Verbindungspool nach passenden inaktiven Verbindungen, die durch vorherige Aufrufe dieser Methode erstellt wurden.
Eine optionale Lua-Tabelle kann als letztes Argument dieser Methode angegeben werden, um verschiedene Verbindungsoptionen festzulegen:
pool: Gibt einen benutzerdefinierten Namen für den verwendeten Verbindungspool an. Wenn weggelassen, wird der Name des Verbindungspools aus der Zeichenfolgenvorlage<host>:<port>oder<unix-socket-path>generiert.
set_timeout
syntax: hp:set_timeout(time)
Setzt den Timeout (in ms) für nachfolgende Operationen, einschließlich der connect-Methode.
ssl_handshake
syntax: hp:ssl_handshake(reused_session?, server_name?, ssl_verify?)
Führt das SSL/TLS-Handshake über die derzeit etablierte Verbindung durch.
Siehe mehr: http://wiki.nginx.org/HttpLuaModule#tcpsock:sslhandshake
set_keepalive
syntax: ok, err = hp:set_keepalive(max_idle_timeout, pool_size)
Versucht, die aktuelle Verbindung in den ngx_lua-Cosocket-Verbindungspool zu legen.
Hinweis Normalerweise wird es automatisch nach der Verarbeitung der Anfrage aufgerufen. Mit anderen Worten, wir können die Verbindung nicht wieder in den Pool zurückgeben, es sei denn, Sie konsumieren alle Daten.
Sie können das maximale Leerlauf-Timeout (in ms) angeben, wenn die Verbindung im Pool ist, und die maximale Größe des Pools für jeden NGINX-Worker-Prozess.
Im Erfolgsfall gibt es 1 zurück. Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
get_reused_times
syntax: times, err = hp:get_reused_times()
Diese Methode gibt die (erfolgreich) wiederverwendeten Zeiten für die aktuelle Verbindung zurück. Im Fehlerfall gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Wenn die aktuelle Verbindung nicht aus dem integrierten Verbindungspool stammt, gibt diese Methode immer 0 zurück, d.h. die Verbindung wurde (noch) nie wiederverwendet. Wenn die Verbindung aus dem Verbindungspool stammt, ist der Rückgabewert immer ungleich null. Diese Methode kann also auch verwendet werden, um zu bestimmen, ob die aktuelle Verbindung aus dem Pool stammt.
close
syntax: ok, err = hp:close()
Schließt die aktuelle Verbindung und gibt den Status zurück.
Im Erfolgsfall gibt es 1 zurück. Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
Anfragen
request
syntax: res, err = hp:request(opts?)
syntax: res, err = hp:request(host, port, opts?)
syntax: res, err = hp:request("unix:/path/to/unix-domain.socket", opts?)
Die opts-Tabelle akzeptiert die folgenden Felder:
version: Setzt die HTTP-Version. Verwenden Sie10für HTTP/1.0 und11für HTTP/1.1. Standardmäßig11.method: Die HTTP-Methodenzeichenfolge. StandardmäßigGET.path: Die Pfadzeichenfolge. Standardmäßig/.query: Gibt Abfrageparameter an. Akzeptiert entweder eine Zeichenfolge oder eine Lua-Tabelle.headers: Eine Tabelle von Anfrage-Headern. Akzeptiert eine Lua-Tabelle.body: Der Anfragekörper als Zeichenfolge oder eine Iteratorfunktion.read_timeout: Setzt das Timeout in Millisekunden für Netzwerk-Leseoperationen speziell.send_timeout: Setzt das Timeout in Millisekunden für Netzwerk-Sendeoperationen speziell.stream: Wenn auftruegesetzt, gibt ein iterierbaresres.body_reader-Objekt anstelle vonres.bodyzurück.maxsize: Setzt die maximale Größe in Bytes, die abgerufen werden soll. Ein Antwortkörper, der größer als dies ist, führt dazu, dass die Funktion einenexceeds maxsize-Fehler zurückgibt. Standardmäßignil, was bedeutet, dass es keine Begrenzung gibt.ssl_verify: Ein Lua-Boolescher Wert, um zu steuern, ob eine SSL-Überprüfung durchgeführt werden soll.
Wenn die Anfrage erfolgreich ist, enthält res die folgenden Felder:
res.status(Zahl): Der Antwortstatus, z.B. 200res.headers(Tabelle): Eine Lua-Tabelle mit Antwort-Headern.res.body(Zeichenfolge): Der einfache Antwortkörper.res.body_reader(Funktion): Eine Iteratorfunktion zum Lesen des Körpers in einem Streaming-Verfahren.res.pipe(httpipe): Eine neue HTTP-Pipe, die standardmäßig den aktuellenbody_readerals Eingabekörper verwendet.
Hinweis Alle Header (Anfrage und Antwort) werden für die Großschreibung normalisiert - z.B. Accept-Encoding, ETag, Foo-Bar, Baz - im normalen HTTP-"Standard."
Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
request_uri
syntax: res, err = hp:request_uri(uri, opts?)
Die einfache Schnittstelle. Optionen, die in der opts-Tabelle bereitgestellt werden, sind die gleichen wie in der generischen Schnittstelle und überschreiben Komponenten, die in der URI selbst gefunden werden.
Gibt ein res-Objekt zurück, das dasselbe ist wie die hp:request-Methode.
Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
res.body_reader
Der body_reader-Iterator kann verwendet werden, um den Antwortkörper in von Ihnen gewählten Chunk-Größen zu streamen, wie folgt:
local reader = res.body_reader
repeat
local chunk, err = reader(8192)
if err then
ngx.log(ngx.ERR, err)
break
end
if chunk then
-- verarbeiten
end
until not chunk
send_request
syntax: ok, err = hp:send_request(opts?)
Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
read_response
syntax: local res, err = hp:read_response(callback?)
Die callback-Tabelle akzeptiert die folgenden Felder:
header_filter: Eine Callback-Funktion für die Filterung von Antwort-Headern
local res, err = hp:read_response{
header_filter = function (status, headers)
if status == 200 then
return 1
end
end }
body_filter: Eine Callback-Funktion für die Filterung des Antwortkörpers
local res, err = hp:read_response{
body_filter = function (chunk)
ngx.print(chunk)
end
}
Zusätzlich gibt es keine Möglichkeit, den Antwortkörper in dieser Methode zu streamen. Wenn die Antwort erfolgreich ist, enthält res die folgenden Felder: res.status, res.headers, res.body.
Hinweis Wenn in der Callback-Funktion true zurückgegeben wird, wird der Filterprozess unterbrochen.
Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
read
syntax: local typ, res, err = hp:read()
Streaming-Parser für die vollständige Antwort.
Der Benutzer muss einfach die Lese-Methode wiederholt aufrufen, bis ein nil-Token-Typ zurückgegeben wird. Für jedes Token, das von der Lese-Methode zurückgegeben wird, überprüfen Sie einfach den ersten Rückgabewert für den aktuellen Token-Typ. Der Token-Typ kann statusline, header, header_end, body, body_end und eof sein. Zum Format des res-Wertes siehe das obige Beispiel. Zum Beispiel halten mehrere Körper-Token jeweils einen Körperdatenchunk, sodass der res-Wert dem Körperdatenchunk entspricht.
Im Fehlerfall gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
eof
syntax: local eof = hp:eof()
Wenn true zurückgegeben wird, bedeutet dies, dass bereits alle Daten konsumiert wurden; andernfalls gibt es noch kein Ende der Anfrage, und Sie müssen hp:close aufrufen, um die Verbindung gewaltsam zu schließen.
Dienstprogramm
parse_uri
syntax: local scheme, host, port, path, args = unpack(hp:parse_uri(uri))
Dies ist eine Hilfsfunktion, die es einfacher macht, die generische Schnittstelle zu verwenden, wenn die Eingabedaten eine URI sind.
get_client_body_reader
syntax: reader, err = hp:get_client_body_reader(chunk_size?)
Gibt eine Iteratorfunktion zurück, die verwendet werden kann, um den Anfragekörper des nachgelagerten Clients in einem Streaming-Verfahren zu lesen. Zum Beispiel:
local req_reader = hp:get_client_body_reader()
repeat
local chunk, err = req_reader(8192)
if err then
ngx.log(ngx.ERR, err)
break
end
if chunk then
-- verarbeiten
end
until not chunk
Dieser Iterator kann auch als Wert für das Feld body in den Anfrageparametern verwendet werden, sodass der Anfragekörper in eine proxied Upstream-Anfrage gestreamt werden kann.
local client_body_reader, err = hp:get_client_body_reader()
local res, err = hp:request{
path = "/helloworld",
body = client_body_reader,
}
GitHub
Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-httpipe.