upload: Streaming-Leser und Parser für das Hochladen von Dateien über HTTP basierend auf dem nginx-module-lua cosocket
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-upload
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-upload
Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.
Dieses Dokument beschreibt lua-resty-upload v0.11, das am 19. Januar 2023 veröffentlicht wurde.
Diese Lua-Bibliothek ist eine Streaming-API für das Hochladen von Dateien für das ngx_lua nginx-Modul:
http://wiki.nginx.org/HttpLuaModule
Der MIME-Typ multipart/form-data wird unterstützt.
Die API dieser Bibliothek gibt Tokens nacheinander zurück. Der Benutzer muss lediglich die read-Methode wiederholt aufrufen, bis ein nil-Token-Typ zurückgegeben wird. Für jedes Token, das von der read-Methode zurückgegeben wird, überprüfen Sie einfach den ersten Rückgabewert auf den aktuellen Token-Typ. Der Token-Typ kann header, body und part end sein. Jedes analysierte multipart/form-data-Formularfeld besteht aus mehreren header-Tokens, die jeden Feldheader halten, mehreren body-Tokens, die jeden Datenchunk des Körpers halten, und einem part end-Flag, das das Ende des Feldes anzeigt.
So funktioniert das Streaming-Lesen. Selbst bei Gigabyte großen Datei-Daten-Eingaben kann der in der Lua-Welt verwendete Speicher klein und konstant sein, solange der Benutzer die Eingabedatenchunks nicht selbst ansammelt.
Diese Lua-Bibliothek nutzt die cosocket-API von ngx_lua, die 100% nicht blockierendes Verhalten gewährleistet.
Beachten Sie, dass mindestens ngx_lua 0.7.9 oder OpenResty 1.2.4.14 erforderlich ist.
Synopsis
server {
location /test {
content_by_lua '
local upload = require "resty.upload"
local cjson = require "cjson"
local chunk_size = 5 -- sollte auf 4096 oder 8192 gesetzt werden
-- für reale Einstellungen
local form, err = upload:new(chunk_size)
if not form then
ngx.log(ngx.ERR, "fehlgeschlagen beim neuen Upload: ", err)
ngx.exit(500)
end
form:set_timeout(1000) -- 1 Sekunde
while true do
local typ, res, err = form:read()
if not typ then
ngx.say("fehlgeschlagen beim Lesen: ", err)
return
end
ngx.say("gelesen: ", cjson.encode({typ, res}))
if typ == "eof" then
break
end
end
local typ, res, err = form:read()
ngx.say("gelesen: ", cjson.encode({typ, res}))
';
}
}
Eine typische Ausgabe des oben definierten /test-Standorts ist:
gelesen: ["header",["Content-Disposition","form-data; name=\"file1\"; filename=\"a.txt\"","Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\""]]
gelesen: ["header",["Content-Type","text\/plain","Content-Type: text\/plain"]]
gelesen: ["body","Hello"]
gelesen: ["body",", wor"]
gelesen: ["body","ld"]
gelesen: ["part_end"]
gelesen: ["header",["Content-Disposition","form-data; name=\"test\"","Content-Disposition: form-data; name=\"test\""]]
gelesen: ["body","value"]
gelesen: ["body","\r\n"]
gelesen: ["part_end"]
gelesen: ["eof"]
gelesen: ["eof"]
Sie können die lua-resty-string Bibliothek verwenden, um SHA-1 und MD5-Digests der Dateidaten inkrementell zu berechnen. Hier ist ein solches Beispiel:
local resty_sha1 = require "resty.sha1"
local upload = require "resty.upload"
local chunk_size = 4096
local form = upload:new(chunk_size)
local sha1 = resty_sha1:new()
local file
while true do
local typ, res, err = form:read()
if not typ then
ngx.say("fehlgeschlagen beim Lesen: ", err)
return
end
if typ == "header" then
local file_name = my_get_file_name(res)
if file_name then
file = io.open(file_name, "w+")
if not file then
ngx.say("fehlgeschlagen beim Öffnen der Datei ", file_name)
return
end
end
elseif typ == "body" then
if file then
file:write(res)
sha1:update(res)
end
elseif typ == "part_end" then
file:close()
file = nil
local sha1_sum = sha1:final()
sha1:reset()
my_save_sha1_sum(sha1_sum)
elseif typ == "eof" then
break
else
-- nichts tun
end
end
Wenn Sie MD5-Prüfziffern für die hochgeladenen Dateien berechnen möchten, verwenden Sie einfach das resty.md5-Modul, das von der lua-resty-string Bibliothek bereitgestellt wird. Es hat eine ähnliche API wie resty.sha1.
Für das Hochladen großer Dateien ist es wichtig, nicht alle Daten im Speicher zu puffern. Das bedeutet, dass Sie Datenchunks niemals in einem riesigen Lua-String oder in einer riesigen Lua-Tabelle ansammeln sollten. Sie müssen die Datenchunks so schnell wie möglich in Dateien schreiben und die Datenchunks sofort wegwerfen (um den Lua-GC sie freigeben zu lassen).
Anstatt die Datenchunks in Dateien zu schreiben (wie im obigen Beispiel gezeigt), können Sie die Datenchunks auch an upstream cosocket-Verbindungen schreiben, wenn Sie die Daten nicht auf lokalen Dateisystemen speichern möchten.
Verwendung
local upload = require "resty.upload"
local form, err = upload:new(self, chunk_size, max_line_size, preserve_body)
chunk_size hat standardmäßig den Wert 4096. Es ist die Größe, die verwendet wird, um Daten vom Socket zu lesen.
max_line_size hat standardmäßig den Wert 512. Es ist die Größenbeschränkung zum Lesen des chunked Body-Headers.
Standardmäßig wird lua-resty-upload den Anfragekörper konsumieren. Für den Proxy-Modus bedeutet dies, dass der Upstream den Körper nicht sieht. Wenn preserve_body auf true gesetzt ist, wird der Anfragekörper beibehalten. Beachten Sie, dass diese Option nicht kostenlos ist. Wenn sie aktiviert ist, verdoppelt sie den Speicherverbrauch von resty.upload.
Siehe auch
- das ngx_lua-Modul
- die lua-resty-string Bibliothek
- die lua-resty-memcached Bibliothek
- die lua-resty-redis Bibliothek
- die lua-resty-mysql Bibliothek
GitHub
Sie finden zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-upload.