Organice un bucket de documentos

CloudflareBeginner
Practicar Ahora

Introducción

Su equipo de soporte necesita un pequeño almacén de documentos. Un objeto está formado por los bytes de un archivo y sus metadatos; un bucket agrupa objetos, y una clave (key) es el nombre completo de un objeto. Las barras en las claves permiten crear prefijos útiles, pero no crean directorios normales del sistema de archivos. Creará un bucket privado, cargará dos documentos sintéticos, inspeccionará sus metadatos, descargará los bytes exactos y eliminará solo el documento seleccionado antes de realizar la limpieza.

Complete primero Conecte LabEx a su cuenta de Cloudflare. En este laboratorio aprenderá a usar el terminal de LabEx, autorizar un dispositivo, confirmar la cuenta de aprendizaje y configurar el ID de la cuenta. Este laboratorio comienza de forma independiente en /home/labex/project/r2-lab, con Node.js 22.22.0, Wrangler 4.131.1 y AWS SDK 3.888.0 ya preparados. En su propio equipo, instale primero Node.js y después instale Wrangler y AWS SDK como dependencias del proyecto con npm install.

Antes de comenzar: su cuenta de aprendizaje debe tener una suscripción activa a R2. La configuración de R2 de Cloudflare incluye un proceso de pago; revíselo si R2 no está activo. Una cuenta Free no activa R2 automáticamente. Consulte los precios para conocer los cargos de almacenamiento y operaciones. Este ejercicio utiliza archivos sintéticos pequeños y ningún dominio adquirido. Necesita permiso para administrar buckets y permiso para crear un token de usuario de R2 limitado a este nuevo bucket. Mantenga deshabilitado el acceso público. Nunca pegue credenciales en esta lección, en el chat ni en capturas de pantalla.

Cree su bucket privado de documentos

En este paso, autorizará esta máquina virtual y creará un bucket temporal. La autorización del dispositivo confirma su cuenta de aprendizaje. La administración de buckets de R2 utiliza un token de API independiente, restringido a esa cuenta.

Inicie Bash para usar la sintaxis de comandos que aparece a continuación. Después, vaya al proyecto preparado y compruebe sus herramientas. Mantenga abierto este mismo terminal para conservar disponibles las variables con los nombres de sus recursos:

bash
cd /home/labex/project/r2-lab
export PATH="$PWD/.tools/node-v22.22.0-linux-x64/bin:$PATH"
node --version
npx wrangler --version

Autorice en su propio navegador el código de dispositivo que se muestra. Antes de conceder el consentimiento, confirme la cuenta de aprendizaje y los ámbitos de lectura de cuenta y usuario solicitados:

npx wrangler login --device --browser=false --scopes account:read user:read
npx wrangler whoami --json

Exija que aparezca loggedIn: true. Lea el nombre de la cuenta aunque solo aparezca una cuenta. Reemplace YOUR_ACCOUNT_ID a continuación por el ID real de 32 caracteres de esa cuenta. openssl rand -hex 6 genera doce caracteres hexadecimales aleatorios para evitar que este laboratorio entre en conflicto con una ejecución anterior. El documento aquí incrustado (here-document) escribe un archivo de configuración estándar; el shell sustituye sus variables por los valores correspondientes.

ACCOUNT_ID=YOUR_ACCOUNT_ID
RUN_ID=$(openssl rand -hex 6)
NAME="labex-c05-r01-$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

Para administrar el bucket, abra la página API Tokens de su perfil de Cloudflare y cree un token personalizado con un nombre relacionado con este laboratorio. Conceda Account → Workers R2 Storage → Edit y limite Account Resources a la cuenta de aprendizaje cuyo ID guardó. Configure una caducidad breve. No incluya otras cuentas ni permisos no relacionados. Este permiso a nivel de cuenta permite crear y eliminar buckets; el token que solo permite operar con objetos en el siguiente paso no puede hacerlo.

Copie el token una sola vez en este indicador oculto de la máquina virtual. umask 077 restringe el archivo a su usuario; read -s oculta lo que escriba. El archivo utiliza la variable de token estándar de Wrangler y queda excluido de Git.

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

Use --env-file=.env.management solo para los comandos de administración de R2; whoami seguirá comprobando la autorización del dispositivo de la máquina virtual.

Coloque --env-file al final de cada comando de Wrangler para que su lista de archivos no incluya el nombre del comando. Después de crear cada bucket, si Wrangler pregunta si debe añadir un enlace a la configuración, escriba n y pulse Enter. La configuración ya contiene el enlace previsto.

npx wrangler r2 bucket create "$BUCKET" --env-file=.env.management

Enumere sus buckets y busque el nombre generado exacto. Los demás buckets pertenecen a otros trabajos; no los modifique.

npx wrangler r2 bucket list --env-file=.env.management

En el Dashboard, abra Storage & databases → R2 → Overview, seleccione este bucket exacto e inspeccione su lista vacía de objetos. En su configuración, deje deshabilitadas la URL de desarrollo pública y los dominios personalizados. El nombre del bucket en el Dashboard confirma su identidad; las comprobaciones de descarga posteriores demostrarán cuáles son los bytes almacenados.

Bucket privado Standard sin objetos

El ejemplo muestra almacenamiento Standard y Public Access Disabled. El nombre del bucket generado será diferente.

Cargue documentos con metadatos

En este paso, dará al SDK acceso únicamente a este bucket y almacenará dos documentos. El tipo de contenido indica a un cliente cómo interpretar los bytes; los metadatos personalizados almacenan sus propias etiquetas pequeñas junto al objeto. Ninguno de los dos es una regla de control de acceso.

La API compatible con S3 permite que los SDK estándar de almacenamiento accedan a R2. Utiliza un par de claves de acceso independiente del token de dispositivo de Wrangler. En R2 Overview, vaya a Account Details → Manage API Tokens y cree un User API token con un nombre relacionado con el nombre del recurso generado en este laboratorio. Elija Object Read & Write, limítelo exactamente a este bucket nuevo y seleccione una caducidad breve si el formulario ofrece esa opción. No elija todos los buckets ni el acceso Admin. Mantenga abierta esta página del token hasta haber guardado el secreto de un solo uso.

Use los siguientes indicadores de Bash en la máquina virtual. read -s oculta lo que escriba; umask 077 hace que el archivo de credenciales solo sea legible por su usuario. Estos nombres son las variables de entorno estándar del AWS SDK. Pegue el Access Key ID y el Secret Access Key en sus respectivos indicadores y pulse Enter. No pegue el valor del token de API general.

En el formulario del token, seleccione 24 hours en TTL y revise el bucket exacto y el permiso Object Read & Write antes de crearlo. Revoque el token al terminar el laboratorio; la caducidad es solo una medida de respaldo.

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

Escriba un cliente reutilizable para el SDK estándar. El SDK requiere una cadena de región; R2 utiliza auto. Leer la configuración existente garantiza que las operaciones de la CLI y del SDK apunten a la misma cuenta y al mismo 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

Ahora cree el programa de carga. PutObjectCommand almacena los bytes en la clave indicada. Ambos documentos son sintéticos; el manual conservado demostrará que una eliminación selectiva posterior no borra las claves no relacionadas.

cat > upload.mjs <<'JS'
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { readFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
await s3.send(new PutObjectCommand({
  Bucket, Key: "documents/report.txt", Body: readFileSync("document.txt"),
  ContentType: "text/plain", Metadata: { team: "blue", revision: "1" }
}));
await s3.send(new PutObjectCommand({
  Bucket, Key: "retained/handbook.txt", Body: readFileSync("retained.txt"),
  ContentType: "text/plain"
}));
console.log("Uploaded two synthetic documents");
JS

--env-file carga los valores de las credenciales sin mostrarlos:

node --env-file=.env.s3 upload.mjs

La línea de éxito se imprime únicamente después de que se completen las dos llamadas a la API con await. La comprobación de la plataforma lee por separado los objetos y los metadatos reales.

Enumere los metadatos y compare los bytes descargados

En este paso, inspeccionará las claves sin descargar todos los objetos y, después, recuperará el informe. ListObjectsV2 enumera las claves, mientras que HeadObject recupera únicamente los metadatos. Este bucket pequeño cabe en una sola página de resultados; en producción, las enumeraciones deben seguir los tokens de continuación cuando IsTruncated sea true.

cat > inspect.mjs <<'JS'
import { ListObjectsV2Command, HeadObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { writeFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
const page = await s3.send(new ListObjectsV2Command({ Bucket }));
console.log(page.Contents.map(object => object.Key));
const metadata = await s3.send(new HeadObjectCommand({ Bucket, Key: "documents/report.txt" }));
console.log({ contentType: metadata.ContentType, metadata: metadata.Metadata });
const object = await s3.send(new GetObjectCommand({ Bucket, Key: "documents/report.txt" }));
writeFileSync("download.txt", await object.Body.transformToByteArray());
JS
node --env-file=.env.s3 inspect.mjs

La lista contiene documents/report.txt y retained/handbook.txt. El informe tiene text/plain, team: blue y revision: 1. El orden de los metadatos en la salida puede variar.

cmp compara los bytes y no muestra nada cuando los archivos coinciden. El mensaje siguiente aparece solo si la comparación se realiza correctamente:

cmp document.txt download.txt && printf "Downloaded bytes match\n"

Actualice la lista de objetos del mismo bucket en el Dashboard y abra los detalles del informe. Compare su clave y tipo de contenido con la salida del SDK. Si el Dashboard actual no muestra un campo de metadatos personalizados, use la salida de la CLI como evidencia de los metadatos.

Tipo, metadatos personalizados y vista previa del informe

El ejemplo muestra text/plain, revision 1, team blue y la vista previa del informe sintético. El nombre del bucket y la fecha de creación serán diferentes.

Elimine únicamente el informe seleccionado

En este paso, eliminará una clave de objeto completa y conservará el manual. Un prefijo no es un directorio que pueda eliminarse de forma recursiva; pase exactamente la clave del informe a la API.

cat > remove-report.mjs <<'JS'
import { DeleteObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3";
import { s3, Bucket } from "./storage.mjs";
await s3.send(new DeleteObjectCommand({ Bucket, Key: "documents/report.txt" }));
const page = await s3.send(new ListObjectsV2Command({ Bucket }));
console.log(page.Contents.map(object => object.Key));
JS
node --env-file=.env.s3 remove-report.mjs

Solo queda retained/handbook.txt. La comprobación de la plataforma también descarga el manual para confirmar que su contenido no ha cambiado. Ejecute esa comprobación antes de continuar con la limpieza total.

Limpie el bucket que creó

En este paso, eliminará el objeto restante y, después, su bucket vacío. Mantenga activas sus credenciales hasta confirmar la eliminación remota.

cat > cleanup.mjs <<'JS'
import { DeleteObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3";
import { s3, Bucket } from "./storage.mjs";
await s3.send(new DeleteObjectCommand({ Bucket, Key: "retained/handbook.txt" }));
const page = await s3.send(new ListObjectsV2Command({ Bucket }));
console.log("Remaining objects:", page.KeyCount);
JS
node --env-file=.env.s3 cleanup.mjs

Exija que aparezca Remaining objects: 0. Si abrió un terminal nuevo, lea el nombre generado del bucket desde la configuración; node -p imprime ese único campo.

BUCKET=$(node -p "JSON.parse(require('fs').readFileSync('wrangler.jsonc')).r2_buckets[0].bucket_name")
npx wrangler r2 bucket delete "$BUCKET" --env-file=.env.management

Cuando se le solicite confirmación, confirme únicamente el bucket exacto del laboratorio. Vuelva a enumerar los buckets; la lista correcta debe omitir ese nombre. Un error de autenticación o de red no demuestra que la eliminación se haya realizado.

npx wrangler r2 bucket list --env-file=.env.management

Actualice la misma lista en el Dashboard y, mientras siga conectado, ejecute la comprobación de la plataforma de este paso.

Revoque la credencial del laboratorio y cierre la sesión

En este paso, cerrará el acceso que dejó este ejercicio. En la página R2 API Tokens, revoque únicamente el token de objetos cuyo nombre corresponde a este laboratorio. En la página API Tokens de su perfil, revoque el token de administración de R2 independiente que creó para este laboratorio. Eliminar un bucket no revoca un token, y cerrar la sesión de Wrangler no revoca las credenciales de S3.

Después de revocar los tokens, elimine el archivo local de credenciales y cierre la sesión de esta máquina virtual:

rm .env.s3 .env.management
npx wrangler logout

Inspeccione la identidad estructurada. Su estado distinto de cero es normal cuando la sesión está cerrada:

npx wrangler whoami --json || true

Exija que aparezca loggedIn: false; mantenga abierta su sesión normal del Dashboard. La plataforma comprueba la eliminación de las credenciales locales y el cierre de sesión de Wrangler. En este laboratorio, ambas revocaciones de tokens son comprobaciones manuales en el Dashboard; no se deducen de la eliminación de los archivos.

Resumen

Creó un bucket privado de R2, almacenó bytes y metadatos de objetos, enumeró y descargó documentos, comprobó una eliminación selectiva y limpió el acceso al bucket.