websocket: WebSocket-Unterstützung für das nginx-module-lua Modul
Installation
Wenn Sie noch kein RPM-Repository-Abonnement 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-websocket
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-websocket
Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.
Dieses Dokument beschreibt lua-resty-websocket v0.14, veröffentlicht am 07. Juni 2026.
Diese Lua-Bibliothek implementiert einen WebSocket-Server und Client-Bibliotheken basierend auf dem ngx_lua Modul.
Diese Lua-Bibliothek nutzt die Cosocket-API von ngx_lua, die ein 100% nicht blockierendes Verhalten gewährleistet.
Bitte beachten Sie, dass nur RFC 6455 unterstützt wird. Frühere Protokollrevisionen wie "hybi-10", "hybi-07" und "hybi-00" werden nicht unterstützt und werden nicht berücksichtigt.
Synopsis
local server = require "resty.websocket.server"
local wb, err = server:new{
timeout = 5000, -- in Millisekunden
max_payload_len = 65535,
}
if not wb then
ngx.log(ngx.ERR, "Fehler beim Erstellen des Websockets: ", err)
return ngx.exit(444)
end
local data, typ, err = wb:recv_frame()
if not data then
if not string.find(err, "timeout", 1, true) then
ngx.log(ngx.ERR, "Fehler beim Empfangen eines Frames: ", err)
return ngx.exit(444)
end
end
if typ == "close" then
-- für typ "close", enthält err den Statuscode
local code = err
-- sende ein Schließ-Frame zurück:
local bytes, err = wb:send_close(1000, "genug, genug!")
if not bytes then
ngx.log(ngx.ERR, "Fehler beim Senden des Schließ-Frames: ", err)
return
end
ngx.log(ngx.INFO, "Schließen mit Statuscode ", code, " und Nachricht ", data)
return
end
if typ == "ping" then
-- sende ein Pong-Frame zurück:
local bytes, err = wb:send_pong(data)
if not bytes then
ngx.log(ngx.ERR, "Fehler beim Senden des Frames: ", err)
return
end
elseif typ == "pong" then
-- einfach das eingehende Pong-Frame verwerfen
else
ngx.log(ngx.INFO, "Empfangen eines Frames vom Typ ", typ, " und Payload ", data)
end
wb:set_timeout(1000) -- ändere das Netzwerk-Timeout auf 1 Sekunde
bytes, err = wb:send_text("Hallo Welt")
if not bytes then
ngx.log(ngx.ERR, "Fehler beim Senden eines Text-Frames: ", err)
return ngx.exit(444)
end
bytes, err = wb:send_binary("blah blah blah...")
if not bytes then
ngx.log(ngx.ERR, "Fehler beim Senden eines Binär-Frames: ", err)
return ngx.exit(444)
end
local bytes, err = wb:send_close(1000, "genug, genug!")
if not bytes then
ngx.log(ngx.ERR, "Fehler beim Senden des Schließ-Frames: ", err)
return
end
Module
resty.websocket.server
Um dieses Modul zu laden, tun Sie einfach Folgendes:
local server = require "resty.websocket.server"
Methoden
new
syntax: wb, err = server:new()
syntax: wb, err = server:new(opts)
Führt den WebSocket-Handshake-Prozess auf der Serverseite durch und gibt ein WebSocket-Serverobjekt zurück.
Im Falle eines Fehlers gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Eine optionale Optionen-Tabelle kann angegeben werden. Die folgenden Optionen sind wie folgt:
-
max_payload_lenGibt die maximale Länge der Payload an, die beim Senden und Empfangen von WebSocket-Frames erlaubt ist. Standardmäßig
65535. *max_recv_lenGibt die maximale Länge der Payload an, die beim Empfangen von WebSocket-Frames erlaubt ist. Standardmäßig der Wert von
max_payload_len. *max_send_lenGibt die maximale Länge der Payload an, die beim Senden von WebSocket-Frames erlaubt ist. Standardmäßig der Wert von
max_payload_len. *send_maskedGibt an, ob maskierte WebSocket-Frames gesendet werden sollen. Wenn es
trueist, werden maskierte Frames immer gesendet. Standardmäßigfalse. *timeoutGibt den Netzwerk-Timeout-Schwellenwert in Millisekunden an. Sie können diese Einstellung später über den Aufruf der Methode
set_timeoutändern. Bitte beachten Sie, dass diese Timeout-Einstellung den HTTP-Antwortheader-Sendeprozess für den WebSocket-Handshake nicht beeinflusst; Sie müssen gleichzeitig die send_timeout Direktive konfigurieren.
set_timeout
syntax: wb:set_timeout(ms)
Setzt die Timeout-Verzögerung (in Millisekunden) für netzwerkbezogene Operationen.
send_text
syntax: bytes, err = wb:send_text(text)
Sendet das text-Argument als unfragmentierten Daten-Frame des Typs text. Gibt die Anzahl der Bytes zurück, die tatsächlich auf TCP-Ebene gesendet wurden.
Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
send_binary
syntax: bytes, err = wb:send_binary(data)
Sendet das data-Argument als unfragmentierten Daten-Frame des Typs binary. Gibt die Anzahl der Bytes zurück, die tatsächlich auf TCP-Ebene gesendet wurden.
Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
send_ping
syntax: bytes, err = wb:send_ping()
syntax: bytes, err = wb:send_ping(msg)
Sendet ein ping-Frame mit einer optionalen Nachricht, die durch das msg-Argument angegeben ist. Gibt die Anzahl der Bytes zurück, die tatsächlich auf TCP-Ebene gesendet wurden.
Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Bitte beachten Sie, dass diese Methode nicht auf ein Pong-Frame vom Remote-Ende wartet.
send_pong
syntax: bytes, err = wb:send_pong()
syntax: bytes, err = wb:send_pong(msg)
Sendet ein pong-Frame mit einer optionalen Nachricht, die durch das msg-Argument angegeben ist. Gibt die Anzahl der Bytes zurück, die tatsächlich auf TCP-Ebene gesendet wurden.
Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
send_close
syntax: bytes, err = wb:send_close()
syntax: bytes, err = wb:send_close(code, msg)
Sendet ein close-Frame mit einem optionalen Statuscode und einer Nachricht.
Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Für eine Liste gültiger Statuscodes siehe das folgende Dokument:
http://tools.ietf.org/html/rfc6455#section-7.4.1
Bitte beachten Sie, dass diese Methode nicht auf ein close-Frame vom Remote-Ende wartet.
send_frame
syntax: bytes, err = wb:send_frame(fin, opcode, payload)
Sendet ein rohes WebSocket-Frame, indem das fin-Feld (boolean Wert), der Opcode und die Payload angegeben werden.
Für eine Liste gültiger Opcodes siehe
http://tools.ietf.org/html/rfc6455#section-5.2
Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Um die maximale Payload-Länge zu steuern, die erlaubt ist, können Sie die Option max_payload_len an den new-Konstruktor übergeben.
Um zu steuern, ob maskierte Frames gesendet werden, können Sie true an die send_masked-Option im new-Konstruktor übergeben. Standardmäßig werden unmaskierte Frames gesendet.
recv_frame
syntax: data, typ, err = wb:recv_frame()
Empfängt ein WebSocket-Frame vom Draht.
Im Falle eines Fehlers gibt es zwei nil-Werte und eine Zeichenfolge zurück, die den Fehler beschreibt.
Der zweite Rückgabewert ist immer der Frame-Typ, der einer von continuation, text, binary, close, ping, pong oder nil (für unbekannte Typen) sein kann.
Für close-Frames gibt es 3 Werte zurück: die zusätzliche Statusnachricht (die eine leere Zeichenfolge sein kann), die Zeichenfolge "close" und eine Lua-Zahl für den Statuscode (falls vorhanden). Für mögliche Schließstatuscodes siehe
http://tools.ietf.org/html/rfc6455#section-7.4.1
Für andere Arten von Frames gibt es einfach die Payload und den Typ zurück.
Für fragmentierte Frames ist der Rückgabewert err die Lua-Zeichenfolge "again".
resty.websocket.client
Um dieses Modul zu laden, tun Sie einfach Folgendes:
local client = require "resty.websocket.client"
Ein einfaches Beispiel zur Demonstration der Verwendung:
local client = require "resty.websocket.client"
local wb, err = client:new()
local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s"
local ok, err, res = wb:connect(uri)
if not ok then
ngx.say("Fehler beim Verbinden: " .. err)
return
end
local data, typ, err = wb:recv_frame()
if not data then
ngx.say("Fehler beim Empfangen des Frames: ", err)
return
end
ngx.say("Empfangen: ", data, " (", typ, "): ", err)
local bytes, err = wb:send_text("Kopie: " .. data)
if not bytes then
ngx.say("Fehler beim Senden des Frames: ", err)
return
end
local bytes, err = wb:send_close()
if not bytes then
ngx.say("Fehler beim Senden des Frames: ", err)
return
end
Methoden
client:new
syntax: wb, err = client:new()
syntax: wb, err = client:new(opts)
Instanziiert ein WebSocket-Clientobjekt.
Im Falle eines Fehlers gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Eine optionale Optionen-Tabelle kann angegeben werden. Die folgenden Optionen sind wie folgt:
-
max_payload_lenGibt die maximale Länge der Payload an, die beim Senden und Empfangen von WebSocket-Frames erlaubt ist. Standardmäßig
65536. *max_recv_lenGibt die maximale Länge der Payload an, die beim Empfangen von WebSocket-Frames erlaubt ist. Standardmäßig der Wert von
max_payload_len. *max_send_lenGibt die maximale Länge der Payload an, die beim Senden von WebSocket-Frames erlaubt ist. Standardmäßig der Wert von
max_payload_len. *send_unmaskedGibt an, ob unmaskierte WebSocket-Frames gesendet werden sollen. Wenn es
trueist, werden unmaskierte Frames immer gesendet. Standardmäßigfalse. RFC 6455 verlangt jedoch, dass der Client maskierte Frames an den Server senden muss, also setzen Sie diese Option niemals auftrue, es sei denn, Sie wissen, was Sie tun. *timeoutGibt den standardmäßigen Netzwerk-Timeout-Schwellenwert in Millisekunden an. Sie können diese Einstellung später über den Aufruf der Methode
set_timeoutändern.
client:connect
syntax: ok, err, res = wb:connect("ws://<host>:<port>/<path>")
syntax: ok, err, res = wb:connect("wss://<host>:<port>/<path>")
syntax: ok, err, res = wb:connect("ws://<host>:<port>/<path>", options)
syntax: ok, err, res = wb:connect("wss://<host>:<port>/<path>", options)
Stellt eine Verbindung zum Remote-WebSocket-Dienstport her und führt den WebSocket-Handshake-Prozess auf der Clientseite durch.
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.
Der dritte Rückgabewert dieser Methode enthält die rohe, unformatierte Antwort (Statuszeile und Header) auf die Handshake-Anfrage. Dies ermöglicht es dem Aufrufer, zusätzliche Validierungen durchzuführen und/oder die Antwortheader zu extrahieren. Wenn die Verbindung wiederverwendet wird und keine Handshake-Anfrage gesendet wird, wird die Zeichenfolge "connection reused" anstelle der Antwort zurückgegeben.
Eine optionale Lua-Tabelle kann als letztes Argument für diese Methode angegeben werden, um verschiedene Verbindungsoptionen anzugeben:
-
protocolsGibt alle Subprotokolle an, die für die aktuelle WebSocket-Sitzung verwendet werden. Es könnte eine Lua-Tabelle sein, die alle Subprotokollnamen enthält, oder einfach eine einzelne Lua-Zeichenfolge. *
originGibt den Wert des
Origin-Anforderungsheaders an. *poolGibt einen benutzerdefinierten Namen für den verwendeten Verbindungspool an. Wenn weggelassen, wird der Name des Verbindungspools aus der Zeichenfolgenvorlage
<host>:<port>generiert. *pool_size
Gibt die Größe des Verbindungspools an. Wenn weggelassen und keine
backlog-Option angegeben wurde, wird kein Pool erstellt. Wenn weggelassen
aber backlog angegeben wurde, wird der Pool mit einer Standardgröße erstellt,
die dem Wert der lua_socket_pool_size
Direktive entspricht.
Der Verbindungspool hält bis zu pool_size aktive Verbindungen,
die bereit sind, von nachfolgenden Aufrufen von connect wiederverwendet zu werden, aber
beachten Sie, dass es keine obere Grenze für die Gesamtzahl der geöffneten Verbindungen
außerhalb des Pools gibt. Wenn Sie die Gesamtzahl der geöffneten
Verbindungen einschränken müssen, geben Sie die backlog-Option an.
Wenn der Verbindungspool seine Größenbeschränkung überschreiten würde, wird die am wenigsten kürzlich verwendete
(gehaltene) Verbindung, die sich bereits im Pool befindet, geschlossen, um Platz für
die aktuelle Verbindung zu schaffen.
Bitte beachten Sie, dass der Cosocket-Verbindungspool pro Nginx-Worker-Prozess
und nicht pro Nginx-Serverinstanz gilt, sodass die hier angegebene Größenbeschränkung auch für jeden einzelnen Nginx-Worker-Prozess gilt. Beachten Sie auch, dass die Größe des Verbindungspools nicht geändert werden kann, sobald er erstellt wurde.
Diese Option wurde erstmals in der Version v0.10.14 eingeführt.
backlog
Wenn angegeben, wird dieses Modul die Gesamtzahl der geöffneten Verbindungen
für diesen Pool begrenzen. Es können jederzeit nicht mehr Verbindungen als pool_size
für diesen Pool geöffnet werden. Wenn der Verbindungspool voll ist, werden nachfolgende
Verbindungsoperationen in eine Warteschlange eingereiht, die dem Wert dieser Option
entspricht (die "backlog"-Warteschlange).
Wenn die Anzahl der eingereihten Verbindungsoperationen gleich backlog ist,
schlagen nachfolgende Verbindungsoperationen fehl und geben nil plus die
Fehlermeldung "too many waiting connect operations" zurück.
Die eingereihten Verbindungsoperationen werden fortgesetzt, sobald die Anzahl der Verbindungen
im Pool weniger als pool_size beträgt.
Die eingereihte Verbindungsoperation wird abgebrochen, sobald sie länger als
connect_timeout, gesteuert durch
settimeouts, in der Warteschlange steht und gibt nil plus
die Fehlermeldung "timeout" zurück.
Diese Option wurde erstmals in der Version v0.10.14 eingeführt.
* ssl_verify
Gibt an, ob während des SSL-Handshakes eine SSL-Zertifikatüberprüfung durchgeführt werden soll, wenn das `wss://`-Schema verwendet wird.
-
headersGibt benutzerdefinierte Header an, die in der Handshake-Anfrage gesendet werden sollen. Die Tabelle sollte Zeichenfolgen im Format
{"a-header: ein Headerwert", "another-header: ein anderer Headerwert"}enthalten. -
client_certGibt ein Client-Zertifikat-Ketten-Cdata-Objekt an, das während des TLS-Handshakes mit dem Remote-Server verwendet wird. Diese Objekte können mit der ngx.ssl.parse_pem_cert Funktion erstellt werden, die von lua-resty-core bereitgestellt wird. Bitte beachten Sie, dass die Angabe der
client_cert-Option auch die Bereitstellung des entsprechendenclient_priv_keyerfordert. Siehe unten. -
client_priv_keyGibt einen privaten Schlüssel an, der der oben genannten
client_cert-Option entspricht. Diese Objekte können mit der ngx.ssl.parse_pem_priv_key Funktion erstellt werden, die von lua-resty-core bereitgestellt wird. -
hostGibt den Wert des
Host-Headers an, der in der Handshake-Anfrage gesendet wird. Wenn nicht angegeben, wird derHost-Header aus dem Hostnamen/Adresse und Port in der Verbindungs-URI abgeleitet. -
server_nameGibt den Servernamen (SNI) an, der beim Durchführen des TLS-Handshakes mit dem Server verwendet werden soll. Wenn nicht angegeben, wird der
host-Wert oder der<host/addr>:<port>aus der Verbindungs-URI verwendet. -
keyGibt den Wert des
Sec-WebSocket-Key-Headers in der Handshake-Anfrage an. Der Wert sollte eine base64-kodierte, 16-Byte-Zeichenfolge sein, die den Anforderungen des Client-Handshakes der WebSocket RFC entspricht. Wenn nicht angegeben, wird ein Schlüssel zufällig generiert.
Der SSL-Verbindungsmodus (wss://) erfordert mindestens ngx_lua 0.9.11 oder OpenResty 1.7.4.1.
client:close
syntax: ok, err = wb:close()
Schließt die aktuelle WebSocket-Verbindung. Wenn noch kein close-Frame gesendet wurde, wird der close-Frame automatisch gesendet.
client:set_keepalive
syntax: ok, err = wb:set_keepalive(max_idle_timeout, pool_size)
Setzt die aktuelle WebSocket-Verbindung sofort in den ngx_lua Cosocket-Verbindungspool.
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 Falle von Fehlern gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
Rufen Sie diese Methode nur an der Stelle auf, an der Sie stattdessen die Methode close aufgerufen hätten. Das Aufrufen dieser Methode versetzt das aktuelle WebSocket-Objekt sofort in den closed-Zustand. Alle nachfolgenden Operationen, die nicht connect() auf dem aktuellen Objekt sind, geben den closed-Fehler zurück.
client:set_timeout
syntax: wb:set_timeout(ms)
Identisch zur set_timeout-Methode der resty.websocket.server Objekte.
client:send_text
syntax: bytes, err = wb:send_text(text)
Identisch zur send_text Methode der resty.websocket.server Objekte.
client:send_binary
syntax: bytes, err = wb:send_binary(data)
Identisch zur send_binary Methode der resty.websocket.server Objekte.
client:send_ping
syntax: bytes, err = wb:send_ping()
syntax: bytes, err = wb:send_ping(msg)
Identisch zur send_ping Methode der resty.websocket.server Objekte.
client:send_pong
syntax: bytes, err = wb:send_pong()
syntax: bytes, err = wb:send_pong(msg)
Identisch zur send_pong Methode der resty.websocket.server Objekte.
client:send_close
syntax: bytes, err = wb:send_close()
syntax: bytes, err = wb:send_close(code, msg)
Identisch zur send_close Methode der resty.websocket.server Objekte.
client:send_frame
syntax: bytes, err = wb:send_frame(fin, opcode, payload)
Identisch zur send_frame Methode der resty.websocket.server Objekte.
Um zu steuern, ob unmaskierte Frames gesendet werden, können Sie true an die send_unmasked-Option im new-Konstruktor übergeben. Standardmäßig werden maskierte Frames gesendet.
client:recv_frame
syntax: data, typ, err = wb:recv_frame()
Identisch zur recv_frame Methode der resty.websocket.server Objekte.
resty.websocket.protocol
Um dieses Modul zu laden, tun Sie einfach Folgendes:
local protocol = require "resty.websocket.protocol"
Methoden
protocol.recv_frame
syntax: data, typ, err = protocol.recv_frame(socket, max_payload_len, force_masking)
Empfängt ein WebSocket-Frame vom Draht.
protocol.build_frame
syntax: frame = protocol.build_frame(fin, opcode, payload_len, payload, masking)
Baut ein rohes WebSocket-Frame.
protocol.send_frame
syntax: bytes, err = protocol.send_frame(socket, fin, opcode, payload, max_payload_len, masking)
Sendet ein rohes WebSocket-Frame.
Automatische Fehlerprotokollierung
Standardmäßig protokolliert das zugrunde liegende ngx_lua Modul Fehler, wenn Socket-Fehler auftreten. Wenn Sie bereits eine ordnungsgemäße Fehlerbehandlung in Ihrem eigenen Lua-Code durchführen, wird empfohlen, diese automatische Fehlerprotokollierung zu deaktivieren, indem Sie die lua_socket_log_errors Direktive von ngx_lua ausschalten, das heißt,
lua_socket_log_errors off;
Einschränkungen
- Diese Bibliothek kann nicht in Codekontexten wie init_by_lua, set_by_lua, log_by_lua und header_filter_by_lua verwendet werden, in denen die ngx_lua Cosocket-API nicht verfügbar ist.
- Die
resty.websocketObjektinstanz kann nicht auf Modulebene in einer Lua-Variablen gespeichert werden, da sie dann von allen gleichzeitigen Anfragen, die vom selben Nginx-Worker-Prozess verarbeitet werden, geteilt wird (siehe http://wiki.nginx.org/HttpLuaModule#Data_Sharing_within_an_Nginx_Worker) und zu schlechten Race-Bedingungen führen kann, wenn gleichzeitige Anfragen versuchen, dieselberesty.websocketInstanz zu verwenden. Sie sollten immerresty.websocketObjekte in lokalen Funktionsvariablen oder in derngx.ctxTabelle initiieren. Diese Orte haben alle ihre eigenen Datenkopien für jede Anfrage.
Siehe auch
- Blogbeitrag WebSockets mit OpenResty von Aapo Talvensaari.
- das ngx_lua Modul: http://wiki.nginx.org/HttpLuaModule
- das WebSocket-Protokoll: http://tools.ietf.org/html/rfc6455
- die lua-resty-upload Bibliothek
- die lua-resty-redis Bibliothek
- die lua-resty-memcached Bibliothek
- die lua-resty-mysql Bibliothek
GitHub
Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-websocket.