Zum Inhalt

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_len

    Gibt die maximale Länge der Payload an, die beim Senden und Empfangen von WebSocket-Frames erlaubt ist. Standardmäßig 65535. * max_recv_len

    Gibt 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_len

    Gibt die maximale Länge der Payload an, die beim Senden von WebSocket-Frames erlaubt ist. Standardmäßig der Wert von max_payload_len. * send_masked

    Gibt an, ob maskierte WebSocket-Frames gesendet werden sollen. Wenn es true ist, werden maskierte Frames immer gesendet. Standardmäßig false. * timeout

    Gibt 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_len

    Gibt die maximale Länge der Payload an, die beim Senden und Empfangen von WebSocket-Frames erlaubt ist. Standardmäßig 65536. * max_recv_len

    Gibt 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_len

    Gibt die maximale Länge der Payload an, die beim Senden von WebSocket-Frames erlaubt ist. Standardmäßig der Wert von max_payload_len. * send_unmasked

    Gibt an, ob unmaskierte WebSocket-Frames gesendet werden sollen. Wenn es true ist, werden unmaskierte Frames immer gesendet. Standardmäßig false. RFC 6455 verlangt jedoch, dass der Client maskierte Frames an den Server senden muss, also setzen Sie diese Option niemals auf true, es sei denn, Sie wissen, was Sie tun. * timeout

    Gibt 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:

  • protocols

    Gibt 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. * origin

    Gibt den Wert des Origin-Anforderungsheaders an. * pool

    Gibt 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.
  • headers

    Gibt 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_cert

    Gibt 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 entsprechenden client_priv_key erfordert. Siehe unten.

  • client_priv_key

    Gibt 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.

  • host

    Gibt den Wert des Host-Headers an, der in der Handshake-Anfrage gesendet wird. Wenn nicht angegeben, wird der Host-Header aus dem Hostnamen/Adresse und Port in der Verbindungs-URI abgeleitet.

  • server_name

    Gibt 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.

  • key

    Gibt 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.websocket Objektinstanz 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, dieselbe resty.websocket Instanz zu verwenden. Sie sollten immer resty.websocket Objekte in lokalen Funktionsvariablen oder in der ngx.ctx Tabelle initiieren. Diese Orte haben alle ihre eigenen Datenkopien für jede Anfrage.

Siehe auch

GitHub

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