Einführung
Eine Supportanwendung muss ein Dokument annehmen und wieder zurücksenden, ohne den Speicher-Bucket öffentlich zu machen. Sie verbinden einen privaten R2-Bucket mit einem Worker, implementieren einen begrenzten Upload und streamen Downloads an die Aufrufer. Ein Stream liefert Datenblöcke, sobald sie verfügbar sind, anstatt den gesamten Download zunächst im Arbeitsspeicher zu sammeln.
Schließen Sie zuerst Organize a Document Bucket sowie die Lektionen zur Worker-Konfiguration und zu Secrets ab. Diese neue VM enthält Node.js 22.22.0, Wrangler 4.131.1, synthetische Dokumente und ein bereitgestelltes Authentifizierungsmodul. Das Modul schützt den Demonstrationsendpunkt mit einem einmalig verwendbaren Token, damit diese Storage-Lektion keinen uneingeschränkten Upload-Service bereitstellt. Die Reparatur der Anwendungsautorisierung lernen Sie später in diesem Kurs.
Vor dem Start benötigt Ihr eigenes Lernkonto ein aktives R2-Abonnement sowie die Berechtigung, einen neuen Bucket und einen Worker zu verwalten. Lesen Sie die R2-Preise; Speicher- und Operationsnutzung sowie die Worker-Nutzung werden getrennt abgerechnet. Eine gekaufte Domain ist nicht erforderlich. Verwenden Sie ausschließlich synthetische Dateien und entfernen Sie am Ende den Worker, die Objekte und den Bucket dieses Labs. Jede VM benötigt eine eigene Autorisierung; Ressourcen aus früheren VMs werden nicht wiederverwendet.
Den Anwendungs-Bucket verbinden
In diesem Schritt autorisieren Sie diese VM und erstellen einen unabhängigen privaten Bucket für die Anwendung. Die Geräteautorisierung bestätigt Ihr Lernkonto. Die Verwaltung von R2-Buckets verwendet ein separates API-Token, 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 Tools. Lassen Sie dasselbe Terminal geöffnet, damit die 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. Bestätigen Sie vor der Zustimmung das Lernkonto sowie die angeforderten Lese-Scopes für Konto und Benutzer:
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_kv:write
npx wrangler whoami --json
Verlangen Sie loggedIn: true. Lesen Sie den Kontonamen auch dann aus, wenn nur ein Konto aufgeführt ist. Ersetzen Sie YOUR_ACCOUNT_ID unten durch die tatsächliche ID dieses Kontos mit 32 Zeichen. openssl rand -hex 6 erzeugt zwölf zufällige Hexadezimalzeichen, damit dieses Lab nicht mit einem früheren Durchlauf kollidiert. Das Here-Dokument schreibt eine Standardkonfigurationsdatei; die Shell ersetzt darin Ihre Variablen.
ACCOUNT_ID=YOUR_ACCOUNT_ID
RUN_ID=$(openssl rand -hex 6)
NAME="labex-c05-r02-$RUN_ID"
BUCKET="$NAME-docs"
cat > wrangler.jsonc <<JSON
{"name":"$NAME","account_id":"$ACCOUNT_ID","main":"src/index.js","workers_dev":true,"compatibility_date":"2026-07-30","r2_buckets":[{"binding":"DOCUMENTS","bucket_name":"$BUCKET"}]}
JSON
Öffnen Sie für die 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 einen kurzen Ablaufzeitraum fest. Schließen Sie keine anderen Konten oder nicht benötigten Berechtigungen ein. Dieses Verwaltungstoken dient der Bucket-Verwaltung, einschließlich Erstellung und Löschung. In diesem Lab greift der Worker über sein DOCUMENTS-Binding auf R2-Objekte zu.
Kopieren Sie das Token einmal in die versteckte Eingabeaufforderung dieser VM. umask 077 beschränkt den Dateizugriff auf Ihren Benutzer; read -s blendet die Eingabe aus. Die Datei verwendet Wranglers Standardvariable für Tokens und ist 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. Der normale Befehl 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 generierten 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; die späteren Download-Prüfungen bestätigen die gespeicherten Bytes.
Die Berechtigung für Worker-Skripte unterstützt die Bereitstellung. Die KV-Berechtigung unterstützt Wranglers Löschbuchhaltung; dieses Lab erstellt keinen KV-Namespace. Das R2-Verwaltungstoken bleibt ein separates, auf das Konto beschränktes Zugangsmittel.
Begrenzte Uploads und Streaming-Downloads implementieren
In diesem Schritt wandeln Sie die Konfigurationsbindung DOCUMENTS in Objektoperationen um. Eine Binding ist ein Laufzeitobjekt, das Cloudflare dem Worker bereitstellt. env.DOCUMENTS verweist auf den privaten Bucket, der über seinen Namen konfiguriert ist; der Worker benötigt dafür kein S3-Secret.
Die bereitgestellte Datei src/auth.js prüft ein nur vorübergehend gültiges Bearer-Token. Unsere Route akzeptiert nur einfache Dokumentnamen mit der Endung .txt. PUT ersetzt die Bytes am ausgewählten Schlüssel. Dieses Beispiel erlaubt höchstens 1 MiB (1.048.576 Bytes), auch wenn Clients keinen Längen-Header mitsenden. Upload-Blöcke werden nur bis zu dieser Grenze gesammelt, sodass R2 einen Body mit bekannter Länge erhalten kann. Downloads übergeben object.body direkt an die Antwort und bleiben gestreamt.
Schreiben Sie den Handler mit diesem Here-Dokument:
cat > src/index.js <<'JS'
import { authorized } from "./auth.js";
const MAX_BYTES = 1024 * 1024;
export default {
async fetch(request, env) {
const path = new URL(request.url).pathname;
if (path === "/health" && request.method === "GET") return new Response("ok");
if (!await authorized(request, env)) return new Response("Unauthorized", { status: 401 });
if (!/^\/documents\/[a-z0-9-]+\.txt$/.test(path)) return new Response("Not found", { status: 404 });
const key = path.slice(1);
if (request.method === "PUT") {
if (Number(request.headers.get("Content-Length")) > MAX_BYTES)
return new Response("Too large", { status: 413 });
// Count actual bytes too: a request may omit Content-Length.
const reader = request.body?.getReader();
if (!reader) return new Response("Body required", { status: 400 });
const chunks = [];
let total = 0;
for (;;) {
const { value, done } = await reader.read();
if (done) break;
total += value.byteLength;
if (total > MAX_BYTES) {
await reader.cancel();
return new Response("Too large", { status: 413 });
}
chunks.push(value);
}
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
await env.DOCUMENTS.put(key, bytes, { httpMetadata: { contentType: "text/plain" } });
return new Response("Stored", { status: 201 });
}
if (request.method !== "GET") return new Response("Method not allowed", { status: 405, headers: { Allow: "GET, PUT" } });
const object = await env.DOCUMENTS.get(key);
if (object === null) return new Response("Not found", { status: 404 });
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set("ETag", object.httpEtag);
headers.set("Cache-Control", "private, no-store");
return new Response(object.body, { headers });
}
};
JS
get() gibt bei einem fehlenden Schlüssel null zurück. Behandeln Sie diesen Fall, bevor Sie den Body lesen. writeHttpMetadata stellt den gespeicherten Inhaltstyp wieder her, und httpEtag ist bereits korrekt in Anführungszeichen gesetzt. private, no-store hält diese geschützten Dokumente aus gemeinsam genutzten Caches heraus.
Erstellen Sie in .dev.vars ein zufälliges Anwendungstoken, das Wrangler für die lokale Entwicklung lädt. Dieses synthetische Lab-Zugangsmittel ist von Ihren Cloudflare-Kontoanmeldedaten getrennt:
umask 077
printf "ACCESS_TOKEN=%s\n" "$(openssl rand -hex 24)" > .dev.vars
Prüfen Sie, ob Wrangler den Code ohne Bereitstellung bündeln kann. Die Plattformprüfung startet eine separate temporäre lokale Laufzeit mit neuen synthetischen Daten, um exakte Bytes, beide Pfade der Größenbegrenzung und das Fehlen zu großer Objekte zu überprüfen:
npx wrangler deploy --dry-run
Die lokale Speichergrenze testen
In diesem Schritt führen Sie den Worker mit lokalem R2-Speicher aus. wrangler dev verwendet standardmäßig eine lokale Simulation, daher erzeugen diese Anfragen kein Cloud-Objekt. Starten Sie den Entwicklungsserver im Hintergrund. $! speichert die Prozess-ID dieses Jobs für die Bereinigung.
npx wrangler dev --ip 127.0.0.1 --port 8787 > dev.log 2>&1 &
DEV_PID=$!
Warten Sie, bis dev.log meldet, dass der Server bereit ist, und laden Sie anschließend das nur vorübergehend gültige Anwendungstoken in dieses Terminal. Geben Sie es nicht aus.
cat dev.log
set -a
source .dev.vars
set +a
Laden Sie die vorbereitete Datei hoch und wieder herunter. --data-binary bewahrt ihre Bytes; -o speichert den Download.
curl -i -X PUT -H "Authorization: Bearer $ACCESS_TOKEN" --data-binary @document.txt http://127.0.0.1:8787/documents/report.txt
curl -fsS -H "Authorization: Bearer $ACCESS_TOKEN" http://127.0.0.1:8787/documents/report.txt -o local-download.txt
cmp document.txt local-download.txt
Verlangen Sie beim Upload 201 Stored und einen erfolgreichen, stillen Vergleich. Testen Sie einen fehlenden Schlüssel sowie einen Upload, der die Grenze um ein Byte überschreitet. Python erstellt nur eine begrenzte synthetische Testdatei:
curl -i -H "Authorization: Bearer $ACCESS_TOKEN" http://127.0.0.1:8787/documents/missing.txt
python3 -c "open('oversized.txt','wb').write(b'x' * (1024 * 1024 + 1))"
curl -i -X PUT -H "Authorization: Bearer $ACCESS_TOKEN" --data-binary @oversized.txt http://127.0.0.1:8787/documents/large.txt
Verlangen Sie 404 Not found und 413 Too large. Diese curl-Aufrufe lassen --fail absichtlich weg, damit die erwarteten HTTP-Fehler lesbar bleiben. Eine HTML-Fehlerseite eines Proxys ist nicht die Antwort der Anwendung. Führen Sie die Plattformprüfung aus, bevor Sie den lokalen Server stoppen.
Die Integration mit dem privaten Bucket bereitstellen und prüfen
In diesem Schritt wiederholen Sie den Dokumentablauf mit echtem R2. Ein lokaler Erfolg beweist weder die Remote-Binding noch den Besitz des Kontos.
Stoppen Sie den Entwicklungsserver und veröffentlichen Sie den Worker:
kill "$DEV_PID"
wait "$DEV_PID" 2>/dev/null || true
npx wrangler deploy
Laden Sie das Anwendungs-Secret mit dem standardmäßigen Bulk-Befehl hoch. .dev.vars wird bei deploy nicht automatisch hochgeladen.
npx wrangler secret bulk .dev.vars
Kopieren Sie die exakte HTTPS-URL von workers.dev aus der Bereitstellungsausgabe nach BASE_URL, ohne abschließenden Schrägstrich. Warten Sie, bis /health ok zurückgibt. Falls die Bereitstellung noch verteilt wird, wiederholen Sie die Abfrage bis zu einer Minute lang.
BASE_URL=https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev
curl -i "$BASE_URL/health"
Laden Sie den Bericht in den Remote-Bucket hoch, laden Sie ihn herunter und vergleichen Sie ihn:
curl -i -X PUT -H "Authorization: Bearer $ACCESS_TOKEN" --data-binary @document.txt "$BASE_URL/documents/report.txt"
curl -fsS -H "Authorization: Bearer $ACCESS_TOKEN" "$BASE_URL/documents/report.txt" -o remote-download.txt
cmp document.txt remote-download.txt
Verlangen Sie 201 Stored und identische Bytes. Wiederholen Sie die negativen Prüfungen gegen den öffentlichen Endpunkt:
curl -i "$BASE_URL/documents/report.txt"
curl -i -H "Authorization: Bearer $ACCESS_TOKEN" "$BASE_URL/documents/missing.txt"
curl -i -X PUT -H "Authorization: Bearer $ACCESS_TOKEN" --data-binary @oversized.txt "$BASE_URL/documents/large.txt"
Verlangen Sie 401 Unauthorized, 404 Not found und 413 Too large. Öffnen Sie im Dashboard diesen Worker und prüfen Sie seine R2-Binding. Öffnen Sie anschließend den exakten Bucket und suchen Sie documents/report.txt. Die öffentliche Entwicklungs-URL und benutzerdefinierte Domains bleiben deaktiviert. Der Worker stellt den Zugriffsweg bereit; der Datenschutz des Buckets bedeutet nicht, dass jede Worker-Route automatisch sicher ist.

Die Zeile DOCUMENTS verbindet diesen Worker mit seinem genauen Bucket. Die generierten Ressourcennamen im Beispiel unterscheiden sich von deinen.

Die Objektzeile zeigt report.txt, text/plain und 41 B; Public Access bleibt Disabled. Namen und Datumsangaben sind Beispiele. Bucket Size kann verzögert noch 0 B anzeigen; die Objektzeile und der erfolgreiche Download belegen, dass der Bericht vorhanden ist.
Die Remote-Anwendung und den Bucket entfernen
In diesem Schritt löschen Sie nur den Worker und die Objekte dieses Labs, solange Sie noch autorisiert sind. Der private Bucket verschwindet nicht, wenn Sie den Worker löschen.
npx wrangler delete
Bestätigen Sie den exakt generierten Workernamen. Löschen Sie das eine hochgeladene Objekt ausdrücklich und anschließend den Bucket:
BUCKET=$(node -p "JSON.parse(require('fs').readFileSync('wrangler.jsonc')).r2_buckets[0].bucket_name")
npx wrangler r2 object delete "$BUCKET/documents/report.txt" --remote --env-file=.env.management
npx wrangler r2 bucket delete "$BUCKET" --env-file=.env.management
Die zu große Anfrage sollte documents/large.txt nicht erstellt haben. Falls der Bucket unerwartet nicht leer ist, prüfen Sie ausschließlich diesen Bucket und entfernen Sie nach der Diagnose des fehlgeschlagenen Größenvertrags den exakten synthetischen Schlüssel. In diesem Fall wurde die vorherige Funktionsprüfung nicht bestanden.
Aktualisieren Sie im Dashboard die Worker- und Bucket-Listen und führen Sie die Plattformprüfung zur Bereinigung aus. Authentifizierungs- oder Netzwerkfehler sind nicht eindeutig und gelten nicht als erfolgreiche Löschung.
Verbleibende Zugangsdaten schließen
In diesem Schritt widerrufen Sie auf der Profilseite API Tokens das Verwaltungstoken dieses Labs, entfernen das lokale Anwendungs-Secret und schließen die VM-Autorisierung. Führen Sie dies erst aus, nachdem die vorherige Bereinigungsprüfung erfolgreich war.
rm .env.management .dev.vars
unset ACCESS_TOKEN
npx wrangler logout
npx wrangler whoami --json || true
Verlangen Sie loggedIn: false. Der Widerruf des Verwaltungstokens ist ein separater manueller Prüfpunkt im Dashboard; das Löschen der lokalen Datei allein widerruft das Token nicht. Lassen Sie die normale Dashboard-Anmeldung und die Tokens anderer Labs unverändert.
Zusammenfassung
Binden Sie privaten R2-Speicher an einen Worker, akzeptieren Sie begrenzte Uploads, streamen Sie exakte Dokumentbytes, behandeln Sie Fehler und entfernen Sie die eigenen Cloud-Ressourcen.



