Einführung
Ein Backup-Uploader sollte erfolgreiche Uploads abschließen und nach einer Unterbrechung aufgegebene Teile freigeben. Sie teilen eine begrenzte synthetische Datei auf, schließen deren Multipart-Sitzung ab und untersuchen eine separate unfertige Sitzung. Dabei dürfen bereits abgeschlossene Objekte nicht verändert werden.
Schließen Sie zuerst die vorherigen Lektionen zu R2-Objekten und bereichsbezogenen Zugangsdaten ab. Diese neue VM enthält Node.js 22.22.0, Wrangler 4.131.1 und AWS SDK 3.888.0. Sie erstellen einen neuen privaten Standard-Bucket und eigene kurzlebige Zugangsdaten. R2 muss aktiviert sein. Lesen Sie die Multipart-Limits und die Preise. Unvollständige Teile werden auf den Speicher angerechnet. Dieses Lab überträgt nur eine kleine synthetische Testdatei und benötigt keine Domain. Verwenden Sie keine früheren Uploads oder Buckets wieder.
Erstellen Sie Ihren privaten Dokument-Bucket
In diesem Schritt autorisieren Sie diese VM und erstellen einen temporären Bucket. Die Geräteautorisierung bestätigt Ihr Lernkonto. Für die Verwaltung von R2-Buckets wird ein separates API-Token benötigt, das auf dieses Konto beschränkt ist.
Starten Sie Bash für die unten verwendete Befehlssyntax. Wechseln Sie anschließend in das vorbereitete Projekt und prüfen Sie die Werkzeuge. Lassen Sie dieses Terminal geöffnet, damit Ihre Variablen mit den Ressourcennamen erhalten bleiben:
bash
cd /home/labex/project/r2-lab
export PATH="$PWD/.tools/node-v22.22.0-linux-x64/bin:$PATH"
node --version
npx wrangler --version
Autorisieren Sie den angezeigten Gerätecode in Ihrem eigenen Browser. Überprüfen Sie vor der Zustimmung das Lernkonto sowie die angeforderten Leseberechtigungen für Konto und Benutzer:
npx wrangler login --device --browser=false --scopes account:read user:read
npx wrangler whoami --json
Verlangen Sie loggedIn: true. Lesen Sie den Kontonamen auch dann ab, wenn nur ein Konto aufgelistet ist. Ersetzen Sie YOUR_ACCOUNT_ID unten durch die tatsächliche 32-stellige ID dieses Kontos. openssl rand -hex 6 erzeugt zwölf zufällige Hexadezimalzeichen, sodass dieses Lab nicht mit einem früheren Durchlauf kollidiert. Das Here-Dokument schreibt eine Standard-Konfigurationsdatei; die Shell setzt Ihre Variablen darin ein.
ACCOUNT_ID=YOUR_ACCOUNT_ID
RUN_ID=$(openssl rand -hex 6)
NAME="labex-c05-r06-$RUN_ID"
BUCKET="$NAME-docs"
cat > wrangler.jsonc <<JSON
{"name":"$NAME","account_id":"$ACCOUNT_ID","compatibility_date":"2026-07-30","r2_buckets":[{"binding":"DOCUMENTS","bucket_name":"$BUCKET"}]}
JSON
Öffnen Sie zur Bucket-Verwaltung die Seite API Tokens Ihres Cloudflare-Profils und erstellen Sie ein benutzerdefiniertes Token mit dem Namen dieses Labs. Gewähren Sie Account → Workers R2 Storage → Edit und beschränken Sie Account Resources auf das Lernkonto, dessen ID Sie gespeichert haben. Legen Sie eine kurze Ablaufzeit fest. Schließen Sie keine anderen Konten oder sachfremden Berechtigungen ein. Dieses Verwaltungstoken dient der Bucket-Verwaltung, einschließlich Erstellung und Löschung. Später in diesem Schritt erstellen Sie ein separates, auf diesen Bucket beschränktes Objekt-Token für die Objektoperationen des S3-SDKs.
Kopieren Sie das Token einmalig in diese versteckte VM-Eingabeaufforderung. umask 077 beschränkt den Dateizugriff auf Ihren Benutzer; read -s blendet die Eingabe aus. Die Datei verwendet Wranglers Standardvariable für Tokens und wird von Git ausgeschlossen.
umask 077
read -r -s -p 'R2 management API token: ' R2_MANAGEMENT_TOKEN; printf '\n'
printf 'CLOUDFLARE_API_TOKEN=%s\n' "$R2_MANAGEMENT_TOKEN" > .env.management
unset R2_MANAGEMENT_TOKEN
Verwenden Sie --env-file=.env.management nur für R2-Verwaltungsbefehle. whoami prüft weiterhin die Geräteautorisierung der VM.
Setzen Sie --env-file an das Ende jedes Wrangler-Befehls, damit dessen Liste von Dateiargumenten nicht auch den Befehlsnamen erfasst. Wenn Wrangler nach dem Erstellen eines Buckets anbietet, eine Bindung zur Konfiguration hinzuzufügen, geben Sie n ein und drücken Sie die Eingabetaste. Die vorgesehene Bindung ist bereits konfiguriert.
npx wrangler r2 bucket create "$BUCKET" --env-file=.env.management
Listen Sie Ihre Buckets auf und suchen Sie den exakt erzeugten Namen. Andere Buckets gehören zu anderen Arbeiten; lassen Sie sie unverändert.
npx wrangler r2 bucket list --env-file=.env.management
Öffnen Sie im Dashboard Storage & databases → R2 → Overview, wählen Sie genau diesen Bucket aus und prüfen Sie die leere Objektliste. Lassen Sie in den Einstellungen die öffentliche Entwicklungs-URL und benutzerdefinierte Domains deaktiviert. Ein Bucket-Name im Dashboard bestätigt die Identität; spätere Download-Prüfungen belegen, dass die gespeicherten Bytes korrekt sind.
Die S3-kompatible API ermöglicht Standard-Speicher-SDKs den Zugriff auf R2. Sie verwendet ein separates Zugriffsschlüsselpaar anstelle des Geräte-Tokens von Wrangler. Öffnen Sie unter R2 Overview den Bereich Account Details → API Tokens → Manage. Erstellen Sie anschließend ein User API token mit dem Namen der in diesem Lab erzeugten Ressource. Wählen Sie Object Read & Write, beschränken Sie das Token auf genau diesen neuen Bucket und wählen Sie eine kurze Ablaufzeit, falls das Formular diese anbietet. Wählen Sie nicht alle Buckets und keinen Admin-Zugriff. Lassen Sie diese Token-Seite geöffnet, bis Sie das einmalig angezeigte Geheimnis gespeichert haben.
Verwenden Sie die folgenden Bash-Eingabeaufforderungen in der VM. read -s blendet die Eingabe aus; umask 077 macht die Zugangsdaten-Datei nur für Ihren Benutzer lesbar. Diese Namen sind die Standard-Umgebungsvariablen des AWS SDK. Fügen Sie die Access Key ID und den Secret Access Key in die jeweiligen Eingabeaufforderungen ein und drücken Sie anschließend Enter. Fügen Sie nicht den Wert des allgemeinen API-Tokens ein.
umask 077
read -r -s -p 'Access Key ID: ' AWS_ACCESS_KEY_ID; printf '\n'
read -r -s -p 'Secret Access Key: ' AWS_SECRET_ACCESS_KEY; printf '\n'
printf 'AWS_ACCESS_KEY_ID=%s\nAWS_SECRET_ACCESS_KEY=%s\n' "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" > .env.s3
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
Erstellen Sie einen wiederverwendbaren Standard-SDK-Client. Das SDK benötigt eine Regionszeichenfolge; für R2 lautet sie auto. Durch das Einlesen der vorhandenen Konfiguration richten CLI- und SDK-Operationen sich auf dasselbe Konto und denselben Bucket.
cat > storage.mjs <<'JS'
import { S3Client } from "@aws-sdk/client-s3";
import { readFileSync } from "node:fs";
const config = JSON.parse(readFileSync("wrangler.jsonc", "utf8"));
export const Bucket = config.r2_buckets[0].bucket_name;
export const s3 = new S3Client({
region: "auto",
endpoint: `https://${config.account_id}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
});
JS
Laden Sie das erhaltene synthetische Handbuch mit Wrangler hoch. Es muss während der Abschluss- und Abbruchvorgänge unverändert bleiben:
npx wrangler r2 object put "$BUCKET/retained/handbook.txt" --remote --file retained.txt --content-type text/plain --env-file=.env.management
Einen begrenzten Multipart-Upload starten
In diesem Schritt starten Sie einen Multipart-Upload: eine serverseitige Upload-Sitzung, die nummerierte Teile entgegennimmt, bevor sie das endgültige Objekt zusammensetzt. Hochgeladene Teile sind noch kein herunterladbares Objekt. Wenn Sie die Upload-ID speichern, können Sie genau diese Sitzung fortsetzen oder abbrechen.
Erstellen Sie mit Python eine synthetische Binärdatei mit 6 MiB. Der erste Teil wird 5 MiB groß sein, der letzte 1 MiB. R2 verlangt unterstützte Teilgrößen; alle Teile außer dem letzten müssen mindestens 5 MiB groß sein und gleich große Teilgrößen verwenden. Diese kleine Testdatei veranschaulicht das Protokoll ohne eine große Übertragung.
python3 - <<'DATA'
from pathlib import Path
Path("archive.bin").write_bytes(bytes(range(256)) * (6 * 1024 * 1024 // 256))
DATA
cat > start.mjs <<'JS'
import { CreateMultipartUploadCommand } from "@aws-sdk/client-s3";
import { writeFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
const Key = "exports/archive.bin";
const result = await s3.send(new CreateMultipartUploadCommand({ Bucket, Key, ContentType: "application/octet-stream" }));
writeFileSync("upload.json", JSON.stringify({ Key, UploadId: result.UploadId }));
console.log("Started multipart upload for", Key);
JS
node --env-file=.env.s3 start.mjs
Bewahren Sie upload.json auf: Die Datei identifiziert diesen Vorgang, bestätigt aber keinen erfolgreichen Abschluss. Führen Sie start nicht unnötig erneut aus. Jeder Aufruf erstellt einen weiteren unvollständigen Upload, der bereinigt werden muss.
Verwenden Sie weiterhin die beim Erstellen gespeicherte Upload-ID. Der getestete R2-Endpunkt lieferte in der Liste eine andere undurchsichtige ID-Zeichenfolge. Vergleichen Sie den genauen Objektschlüssel und bestätigen Sie die aktive Sitzung mit der gespeicherten ID und ListParts.
Geordnete Teile hochladen und das Objekt abschließen
In diesem Schritt senden Sie die beiden Teile und teilen R2 mit, welche von den Uploads zurückgegebenen Teile das endgültige Objekt bilden. Die Teilenummern beginnen bei 1. Die Abschlussanforderung enthält jedes ETag genau so, wie es vom Upload des jeweiligen Teils zurückgegeben wurde. Es entspricht nicht dem Hashen der vollständigen Quelldatei durch Sie selbst.
cat > complete.mjs <<'JS'
import { UploadPartCommand, CompleteMultipartUploadCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { readFileSync, writeFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
const { Key, UploadId } = JSON.parse(readFileSync("upload.json", "utf8"));
const bytes = readFileSync("archive.bin");
const size = 5 * 1024 * 1024;
const Parts = [];
for (let offset = 0, PartNumber = 1; offset < bytes.length; offset += size, PartNumber++) {
const result = await s3.send(new UploadPartCommand({ Bucket, Key, UploadId, PartNumber, Body: bytes.subarray(offset, offset + size) }));
Parts.push({ PartNumber, ETag: result.ETag });
console.log("Uploaded part", PartNumber);
}
await s3.send(new CompleteMultipartUploadCommand({ Bucket, Key, UploadId, MultipartUpload: { Parts } }));
const object = await s3.send(new GetObjectCommand({ Bucket, Key }));
writeFileSync("completed.bin", await object.Body.transformToByteArray());
console.log("Completed and downloaded", Key);
JS
node --env-file=.env.s3 complete.mjs
Verlangen Sie zwei Zeilen für die hochgeladenen Teile, gefolgt von der Abschlusszeile. Vergleichen Sie die tatsächlich heruntergeladene Datei Byte für Byte:
cmp archive.bin completed.bin && printf "Multipart bytes match\n"
Das ETag eines Multipart-Objekts ist nicht unbedingt ein MD5-Hash der fertigen Datei. Der Bytevergleich weist die unveränderte Übertragung des Inhalts direkt nach. Öffnen Sie im Dashboard den Bucket dieses Labs und prüfen Sie exports/archive.bin. Das erhaltene Handbuch muss weiterhin vorhanden sein.
Deaktiviere View prefixes as folders, um beide vollständigen Objektschlüssel wie im Beispiel zu sehen. Dein erzeugter Bucket-Name ist anders. 6.29 MB ist die dezimale Anzeige von 6 MiB (6.291.456 Bytes). Die obere Übersicht Bucket Size: 0 B kann verzögert sein; bestätige den Inhalt anhand der Objektzeilen und der über die API geprüften Bytes.

Einen unvollständigen Upload untersuchen
In diesem Schritt lassen Sie absichtlich einen neuen Upload unvollständig und listen anschließend die Sitzung sowie ihre Teile auf. Unvollständige Teile belegen Speicher, obwohl eine normale Objektliste keine fertige Datei anzeigt. Deshalb benötigt die Bereinigung neben einem Objektinventar auch ein Upload-Inventar.
cat > abandon.mjs <<'JS'
import { CreateMultipartUploadCommand, UploadPartCommand, ListMultipartUploadsCommand, ListPartsCommand } from "@aws-sdk/client-s3";
import { readFileSync, writeFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
const Key = "temporary/unfinished.bin";
const result = await s3.send(new CreateMultipartUploadCommand({ Bucket, Key }));
const UploadId = result.UploadId;
writeFileSync("abandoned.json", JSON.stringify({ Key, UploadId }));
await s3.send(new UploadPartCommand({ Bucket, Key, UploadId, PartNumber: 1, Body: readFileSync("archive.bin").subarray(0, 5 * 1024 * 1024) }));
const uploads = await s3.send(new ListMultipartUploadsCommand({ Bucket }));
console.log(uploads.Uploads.map(upload => ({ key: upload.Key, uploadId: upload.UploadId })));
const parts = await s3.send(new ListPartsCommand({ Bucket, Key, UploadId }));
console.log(parts.Parts.map(part => ({ part: part.PartNumber, bytes: part.Size })));
JS
node --env-file=.env.s3 abandon.mjs
Die Multipart-Liste enthält temporary/unfinished.bin. Die ListParts-Anfrage verwendet die gespeicherte Upload-ID und muss Teil 1 mit 5,242,880 Bytes liefern. Vergleichen Sie nicht den ID-Text der Liste mit der gespeicherten ID und erstellen Sie keine weitere Sitzung für eine erneute Abfrage. Verwenden Sie die gespeicherte ID mit den Listen-APIs und führen Sie die Prüfung aus, solange dieser Upload existiert.
Nur die aufgegebene Sitzung abbrechen
In diesem Schritt geben Sie die unfertigen Teile frei, indem Sie genau deren Upload-ID abbrechen. Ein Abbruch unterscheidet sich vom Löschen eines abgeschlossenen Objekts. Sowohl das abgeschlossene Archiv als auch das Handbuch müssen erhalten bleiben.
cat > abort.mjs <<'JS'
import { AbortMultipartUploadCommand, ListMultipartUploadsCommand } from "@aws-sdk/client-s3";
import { readFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
const { Key, UploadId } = JSON.parse(readFileSync("abandoned.json", "utf8"));
await s3.send(new AbortMultipartUploadCommand({ Bucket, Key, UploadId }));
const uploads = await s3.send(new ListMultipartUploadsCommand({ Bucket }));
console.log("Incomplete uploads:", uploads.Uploads || []);
JS
node --env-file=.env.s3 abort.mjs
Dieser neue Bucket sollte nun eine leere Liste der Multipart-Uploads anzeigen. Die Plattformprüfung lädt außerdem beide abgeschlossenen Objekte herunter und bestätigt damit, dass sie unverändert geblieben sind. Interpretieren Sie niemals eine fehlgeschlagene Auflistung als leere Liste.
Abgeschlossene Dateien und den Bucket bereinigen
In diesem Schritt entfernen Sie genau die beiden abgeschlossenen Objekte, nachdem die Abbruchprüfung erfolgreich war. Die ausdrückliche Bereinigung wartet nicht auf die standardmäßige Lebenszyklusregel für unvollständige Uploads.
npx wrangler r2 object delete "$BUCKET/exports/archive.bin" --remote --env-file=.env.management
npx wrangler r2 object delete "$BUCKET/retained/handbook.txt" --remote --env-file=.env.management
npx wrangler r2 bucket delete "$BUCKET" --env-file=.env.management
npx wrangler r2 bucket list --env-file=.env.management
Bestätigen Sie ausschließlich den erzeugten Namen dieses Buckets. Verlangen Sie, dass er in einer erfolgreichen Inventarliste fehlt, und führen Sie die Plattformprüfung zur Bereinigung aus, bevor Sie die Zugangsdaten widerrufen.
Die Lab-Zugangsdaten widerrufen und abmelden
In diesem Schritt schließen Sie den durch diese Übung verbleibenden Zugriff. Widerrufen Sie auf der Seite R2 API Tokens nur das nach diesem Lab benannte Objekt-Token. Widerrufen Sie auf der Seite API Tokens Ihres Profils das separate R2-Verwaltungs-Token, das Sie für dieses Lab erstellt haben. Das Löschen eines Buckets widerruft kein Token, und die Abmeldung von Wrangler widerruft keine S3-Zugangsdaten.
Entfernen Sie nach dem Widerruf die lokale Zugangsdaten-Datei und melden Sie diese VM ab:
rm .env.s3 .env.management
npx wrangler logout
Untersuchen Sie die strukturierte Identität. Der Status ungleich null ist im abgemeldeten Zustand zu erwarten:
npx wrangler whoami --json || true
Verlangen Sie loggedIn: false; bleiben Sie im normalen Dashboard angemeldet. Die Plattformprüfungen kontrollieren das Entfernen der lokalen Zugangsdaten und die Abmeldung von Wrangler. Der Widerruf beider Tokens erfolgt in diesem Kandidaten manuell über das Dashboard und wird nicht aus dem Löschen der Dateien abgeleitet.
Zusammenfassung
Schließen Sie ein Multipart-Objekt mit exakt übereinstimmenden Bytes ab, untersuchen und verwerfen Sie unfertige Teile, erhalten Sie andere Objekte und bereinigen Sie die Speicherzugangsdaten.



