OBS/Kostenpflichtige Module/RESTServer/Datei-Upload: Unterschied zwischen den Versionen
Die Seite wurde neu angelegt: „{{Kostenpflichtige Module}} = Datei-Upload = Ein Endpunkt nimmt Dateien nur entgegen, wenn er dafür freigeschaltet ist (<code>re_upload = 1</code>, siehe Endpunkte). Dann gilt nicht das JSON-Body-Limit von 10 MB, sondern die pro Endpunkt konfigurierte Grösse (<code>re_upload_size</code>, Standard 25 MB; Überschreitung -> '''413'''). Diese Seite beschreibt die '''Übertragung''' - was ein…“ |
Keine Bearbeitungszusammenfassung |
||
| Zeile 113: | Zeile 113: | ||
{{Hinweis|Der Upload-Status liegt prozesslokal im Speicher. Nach einem Neustart des Servers muss ein unvollständiger Upload neu begonnen werden.}} | {{Hinweis|Der Upload-Status liegt prozesslokal im Speicher. Nach einem Neustart des Servers muss ein unvollständiger Upload neu begonnen werden.}} | ||
== Komprimierte Uploads == | |||
Ein Upload-Körper mit dem Header <code>Content-Encoding</code> wird mit '''415 Unsupported Media Type''' abgewiesen - bei beiden Verfahren, einfach wie chunked. | |||
Der Grund ist nicht Bequemlichkeit. Bei einem chunked Upload bliebe offen, ob <code>Content-Range</code> die gepackten oder die rohen Bytes zählt, und die SHA256-Prüfsumme bezöge sich nach einem Entpacken auf eine andere Datei, als der Client gesendet hat. Etablierte Protokolle - tus, S3 Multipart, Google Resumable Upload, Azure Blob - behandeln Kompression aus demselben Grund als Eigenschaft der '''gespeicherten Datei''' und nicht der Übertragung. | |||
Wer gepackt hochladen will, packt die Datei '''selbst''' und lädt sie als <code>export.csv.gz</code> hoch. Offsets, Prüfsumme und Wiederaufnahme stimmen dann, und das Endpunkt-Skript bekommt Name und Typ wie gewohnt über <code>_OBS_UPLOAD_NAME</code> und <code>_OBS_UPLOAD_CONTENTTYPE</code>. | |||
Version vom 15. September 2026, 11:00 Uhr
Datei-Upload
Ein Endpunkt nimmt Dateien nur entgegen, wenn er dafür freigeschaltet ist
(re_upload = 1, siehe
Endpunkte). Dann gilt nicht
das JSON-Body-Limit von 10 MB, sondern die pro Endpunkt konfigurierte Grösse
(re_upload_size, Standard 25 MB; Überschreitung -> 413).
Diese Seite beschreibt die Übertragung - was ein Client senden muss und was
der Server antwortet. Was das Skript davon sieht, sind vier Aufrufe
(oReader.UploadPath(), UploadName(),
UploadType(), UploadSha()) und steht unter
Scripting.
Ein vollständiges Beispiel zeigt
Beispiel 6.
verschiebt sie nicht selbst. Übernimmt das Skript sie nicht an ihren
Zielort, bleibt sie dort liegen.Einfacher Upload (multipart/form-data)
Eine Datei pro Request. Name und Content-Type stammen aus der
Content-Disposition der Datei-Partie (filename=). Der
Server speichert die erste Datei-Partie und ruft das Skript auf.
Die übrigen Partien des Formulars - alles ohne filename= -
liest das Skript über oReader.Form('<name>'). Der Wert ist UTF-8 und
auf 1024 Zeichen begrenzt, der Name auf Buchstaben, Ziffern und Unterstrich
reduziert. Zusatzangaben lassen sich damit im selben Request mitschicken, ohne sie
an die URL zu hängen:
procedure Post(oReader: TxRestReader; oWriter: TxRestWriter);
var cPfad : string;
cName : string;
cTyp : string;
cBemerk: string;
begin
cPfad := oReader.UploadPath();
cName := oReader.UploadName();
cTyp := oReader.UploadType();
cBemerk := oReader.Form('bemerkung'); // Formularfeld derselben Uebertragung
// ... Datei aus cPfad ins DMS / Zielverzeichnis uebernehmen ...
oWriter.Str('status' , 'ok');
oWriter.Str('dateiname', cName);
oWriter.Status(201);
end;
Resumable/Chunked Upload (Content-Range)
Für grosse Dateien überträgt der Client die Datei in Teilstücken (Chunks) mit dem
Header Content-Range: bytes START-END/TOTAL. Der Server hängt die
Chunks sequentiell an eine Session-Datei an und behandelt unvollständige
Uploads selbst - das Endpunkt-Skript läuft erst beim vollständigen Upload,
und dann liefern oReader.UploadPath(), UploadName() und UploadType()
dasselbe wie beim einfachen Upload. Für die Teilstücke läuft es nicht.
Name und Content-Type sind im Content-Range-Protokoll nicht enthalten;
der Client liefert sie deshalb im ersten Chunk über den Header
Upload-Metadata (Format wie bei tus: kommagetrennte Paare
schlüssel base64wert, Werte Base64-kodiert):
Upload-Metadata: filename ZmlsZS5wZGY=,filetype YXBwbGljYXRpb24vcGRm
Erkannt werden die Schlüssel filename (Pflicht) und
filetype (optional). Fehlt filename im ersten Chunk,
wird der Upload mit 400 abgelehnt, ohne dass eine Datei angelegt wird.
Folge-Chunks und Statusabfragen müssen die Metadaten nicht erneut senden.
Ablauf (vom Client gesteuert, der Server antwortet jeweils):
| Request | Server-Antwort |
|---|---|
Erster Chunk Content-Range: bytes 0-1048575/5000000 + Upload-Metadata |
308 Resume Incomplete + Header Upload-Id, Upload-Offset, Range
|
weitere Chunks (jeweils Upload-Id mitsenden) |
308 mit aktualisiertem Upload-Offset
|
| letzter Chunk (Bereich erreicht TOTAL) | normale Skript-Antwort (z.B. 200/201) |
Statusabfrage Content-Range: bytes */5000000 |
aktueller Upload-Offset, ohne anzuhängen (Resume)
|
| Header | Richtung | Bedeutung |
|---|---|---|
| Content-Range | Request | bytes START-END/TOTAL; bytes */TOTAL nur als Statusabfrage
|
| Upload-Metadata | Request | tus-Metadaten im ersten Chunk: filename (Pflicht), filetype (optional), Base64-kodiert
|
| Upload-Id | Request/Response | Session-Kennung. Fehlt sie im ersten Request, erzeugt der Server eine und gibt sie zurück; alle Folge-Chunks müssen sie mitsenden. |
| Upload-Offset | Response | Anzahl der bereits gespeicherten Bytes (= Startoffset des nächsten Chunks) |
| Range | Response | Bereits gespeicherter Bereich (bytes=0-N)
|
Der Server hängt einen Chunk nur an, wenn START dem bereits gespeicherten Stand entspricht. Bei Abweichung (doppelter Chunk, Lücke) wird nicht angehängt, sondern der aktuelle Upload-Offset zurückgemeldet - der Client setzt ab dort neu auf. Eine separate Statusabfrage ist für ein Resume daher nicht zwingend nötig.
Überschreitet ein Chunk bzw. die Gesamtgrösse das Limit (re_upload_size), antwortet der Server mit 413 Payload Too Large.
Komprimierte Uploads
Ein Upload-Körper mit dem Header Content-Encoding wird mit 415 Unsupported Media Type abgewiesen - bei beiden Verfahren, einfach wie chunked.
Der Grund ist nicht Bequemlichkeit. Bei einem chunked Upload bliebe offen, ob Content-Range die gepackten oder die rohen Bytes zählt, und die SHA256-Prüfsumme bezöge sich nach einem Entpacken auf eine andere Datei, als der Client gesendet hat. Etablierte Protokolle - tus, S3 Multipart, Google Resumable Upload, Azure Blob - behandeln Kompression aus demselben Grund als Eigenschaft der gespeicherten Datei und nicht der Übertragung.
Wer gepackt hochladen will, packt die Datei selbst und lädt sie als export.csv.gz hoch. Offsets, Prüfsumme und Wiederaufnahme stimmen dann, und das Endpunkt-Skript bekommt Name und Typ wie gewohnt über _OBS_UPLOAD_NAME und _OBS_UPLOAD_CONTENTTYPE.