Introdução
Um serviço de exportação deve remover downloads temporários sem excluir documentos retidos. Você aplicará regras de expiração por prefixo, transição de classe de armazenamento e limpeza de uploads incompletos a um bucket privado novo. Em seguida, inspecionará os metadados reais da política e dos objetos.
Conclua primeiro o gerenciamento de objetos e a limpeza de uploads multipart. Esta nova VM usa Node.js 22.22.0, Wrangler 4.131.1 e AWS SDK 3.888.0. O R2 deve estar ativo, e você precisa de permissão para configurar o novo bucket. Consulte o comportamento do ciclo de vida e os preços, incluindo a duração mínima e as tarifas de recuperação do Infrequent Access. O objeto de teste permanece no armazenamento Standard e é excluído explicitamente durante esta sessão. As verificações de aceitação validam as regras aplicadas e os metadados atuais, não uma exclusão ou transição ocorrida dias depois. Nenhum domínio é necessário.
Criar seu bucket privado de documentos
Nesta etapa, você autoriza esta VM e cria um bucket descartável. A autorização do dispositivo confirma sua conta de aprendizado. O gerenciamento de buckets do R2 usa um token de API separado, restrito a essa conta.
Inicie o Bash para usar a sintaxe dos comandos abaixo. Depois, acesse o projeto preparado e verifique as ferramentas. Mantenha este mesmo terminal aberto para que as variáveis com os nomes dos recursos continuem disponíveis:
bash
cd /home/labex/project/r2-lab
export PATH="$PWD/.tools/node-v22.22.0-linux-x64/bin:$PATH"
node --version
npx wrangler --version
Autorize o código de dispositivo exibido no seu próprio navegador. Confirme a conta de aprendizado e os escopos solicitados de leitura da conta e do usuário antes de conceder o consentimento:
npx wrangler login --device --browser=false --scopes account:read user:read
npx wrangler whoami --json
Exija loggedIn: true. Leia o nome da conta mesmo que apenas uma conta seja listada. Substitua YOUR_ACCOUNT_ID abaixo pelo ID real de 32 caracteres dessa conta. openssl rand -hex 6 gera doze caracteres hexadecimais aleatórios para evitar que este laboratório entre em conflito com uma execução anterior. O here-document cria um arquivo de configuração padrão; o shell substitui nele as suas variáveis.
ACCOUNT_ID=YOUR_ACCOUNT_ID
RUN_ID=$(openssl rand -hex 6)
NAME="labex-c05-r07-$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 gerenciar o bucket, abra a página API Tokens do seu perfil da Cloudflare e crie um token personalizado com o nome deste laboratório. Conceda Account → Workers R2 Storage → Edit e restrinja Account Resources à conta de aprendizado cujo ID você salvou. Defina uma expiração curta. Não inclua outras contas nem permissões não relacionadas. Este token de gerenciamento serve para administrar buckets, incluindo sua criação e exclusão. Mais adiante nesta mesma etapa, você criará um token de objetos separado, limitado a este bucket, para as operações do SDK do S3.
Copie o token uma única vez para este prompt da VM oculta. umask 077 restringe o arquivo ao seu usuário; read -s oculta a entrada. O arquivo usa a variável de token padrão do Wrangler e é excluído do 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 somente nos comandos de gerenciamento do R2; o whoami comum continuará verificando a autorização do dispositivo da VM.
Coloque --env-file no final de cada comando do Wrangler para que a lista de argumentos de arquivos não inclua o nome do comando. Depois de criar cada bucket, se o Wrangler perguntar se deve adicionar uma vinculação à configuração, digite n e pressione Enter. A configuração já contém a vinculação necessária.
npx wrangler r2 bucket create "$BUCKET" --env-file=.env.management
Liste seus buckets e encontre o nome gerado exato. Os outros buckets pertencem a outros trabalhos; não os altere.
npx wrangler r2 bucket list --env-file=.env.management
No Dashboard, abra Storage & databases → R2 → Overview, selecione exatamente este bucket e verifique se a lista de objetos está vazia. Nas configurações dele, mantenha desativados o URL público de desenvolvimento e os domínios personalizados. O nome do bucket no Dashboard confirma a identidade; as verificações de download posteriores comprovarão os bytes armazenados.
A API compatível com S3 permite que SDKs de armazenamento padrão acessem o R2. Ela usa um par de chave de acesso separado, em vez do token de dispositivo do Wrangler. Em R2 Overview, use Account Details → API Tokens → Manage e crie um User API token com o nome do recurso gerado para este laboratório. Escolha Object Read & Write, restrinja o token exatamente a este novo bucket e selecione uma expiração curta, se o formulário oferecer essa opção. Não escolha todos os buckets nem o acesso Admin. Mantenha esta página do token aberta até armazenar o segredo, que só será exibido uma vez.
Use os prompts do Bash a seguir na VM. read -s oculta a entrada; umask 077 faz com que o arquivo de credenciais possa ser lido somente pelo seu usuário. Esses nomes são as variáveis de ambiente padrão do AWS SDK. Cole o Access Key ID e o Secret Access Key nos respectivos prompts e pressione Enter. Não cole o valor do token de API geral.
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
Crie um cliente reutilizável do SDK padrão. O SDK exige uma string de região; no R2, use auto. A leitura da configuração existente mantém as operações da CLI e do SDK direcionadas à mesma conta e ao mesmo 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
Aplicar regras de ciclo de vida específicas por prefixo
Nesta etapa, você configura uma lifecycle policy, ou seja, um conjunto de ações de armazenamento que o R2 aplica conforme os objetos envelhecem. As exportações temporárias devem expirar, enquanto os manuais retidos permanecem fora dessas regras. Uma transição de classe de armazenamento altera a classe de cobrança e acesso; ela não exclui o objeto.
Este novo bucket descartável usará duas regras: os objetos em temporary/ expiram depois de dois dias, e os uploads não concluídos sob esse prefixo são cancelados depois de um dia; os objetos em archive/ fazem a transição para Infrequent Access depois de trinta dias. Nada se aplica a retained/.
A API expressa as idades em segundos: um dia equivale a 86.400 segundos. Grave a política com um here-document entre aspas para preservar o JSON:
cat > lifecycle.json <<'JSON'
{
"rules": [
{
"id": "temporary-exports",
"enabled": true,
"conditions": {
"prefix": "temporary/"
},
"deleteObjectsTransition": {
"condition": {
"type": "Age",
"maxAge": 172800
}
},
"abortMultipartUploadsTransition": {
"condition": {
"type": "Age",
"maxAge": 86400
}
}
},
{
"id": "archive-transition",
"enabled": true,
"conditions": {
"prefix": "archive/"
},
"storageClassTransitions": [
{
"condition": {
"type": "Age",
"maxAge": 2592000
},
"storageClass": "InfrequentAccess"
}
]
}
]
}
JSON
npx wrangler r2 bucket lifecycle set "$BUCKET" --file lifecycle.json --env-file=.env.management
npx wrangler r2 bucket lifecycle list "$BUCKET" --env-file=.env.management
O comando set substitui a política; portanto, confirme que você está trabalhando somente com este novo bucket do laboratório. Exija exatamente os dois prefixos, o estado habilitado e as idades corretas. Não aplique essa substituição a um bucket de uma aplicação existente. No Dashboard, abra Settings → Object Lifecycle Rules do mesmo bucket e inspecione as ações sem alterá-las.
Limite de custo: o Infrequent Access cobra tarifas de recuperação e exige uma duração mínima de armazenamento. Este laboratório configura uma transição futura e remove seus novos objetos Standard durante a limpeza. Você não aguardará trinta dias, não forçará uma transição e não afirmará que uma transição realmente ocorreu.
Esta tela real do Dashboard mostra ações futuras configuradas: excluir objetos temporary/ após 2 dias, abortar uploads incompletos desse prefixo após 1 dia e mover objetos archive/ para Infrequent Access após 30 dias. Ela não comprova que esses prazos passaram nem que as ações foram executadas. A próxima etapa verifica os metadados atuais; retained/ fica fora dos dois prefixos.

Inspecionar os metadados de expiração recém-aplicados
Nesta etapa, você fará upload de novos objetos depois de aplicar a política. A documentação do R2 informa que novos objetos refletem uma expiração aplicável em x-amz-expiration; objetos existentes podem levar mais tempo para refletir uma regra alterada. O SDK expõe esse cabeçalho como Expiration.
cat > seed.mjs <<'JS'
import { PutObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
import { readFileSync } from "node:fs";
import { s3, Bucket } from "./storage.mjs";
for (const Key of ["temporary/export.txt", "archive/export.txt"]) {
await s3.send(new PutObjectCommand({ Bucket, Key, Body: readFileSync("document.txt"), ContentType: "text/plain" }));
}
await s3.send(new PutObjectCommand({ Bucket, Key: "retained/handbook.txt", Body: readFileSync("retained.txt"), ContentType: "text/plain" }));
for (const Key of ["temporary/export.txt", "archive/export.txt", "retained/handbook.txt"]) {
const head = await s3.send(new HeadObjectCommand({ Bucket, Key }));
console.log({ key: Key, expiration: head.Expiration || "none", storageClass: head.StorageClass || "STANDARD" });
}
JS
node --env-file=.env.s3 seed.mjs
Exija uma data de expiração para temporary/export.txt, nenhuma expiração de exclusão para o manual retido e armazenamento Standard para o novo objeto de arquivo. A transição futura é comprovada pela regra remota, não por uma classe de armazenamento IA atual. Se os metadados de expiração esperados do novo objeto não aparecerem, inspecione o prefixo e a política aplicados; não considere isso uma verificação de expiração bem-sucedida.
Baixe o objeto retido e compare seus bytes originais:
npx wrangler r2 object get "$BUCKET/retained/handbook.txt" --remote --file retained-download.txt --env-file=.env.management
cmp retained.txt retained-download.txt
Uma leitura bem-sucedida da política e um objeto retido legível estabelecem o resultado delimitado deste laboratório. A exclusão real do ciclo de vida é assíncrona e pode ocorrer depois da expiração nominal; este laboratório não avalia um evento ocorrido horas mais tarde.
Esvaziar explicitamente o armazenamento do laboratório
Nesta etapa, você removerá os três objetos de teste agora, em vez de depender das ações futuras do ciclo de vida. Nenhum upload incompleto foi criado neste laboratório, mas liste esse inventário também: as listagens de objetos, sozinhas, não comprovam que um bucket não tem partes inacabadas.
cat > empty.mjs <<'JS'
import { DeleteObjectCommand, ListObjectsV2Command, ListMultipartUploadsCommand } from "@aws-sdk/client-s3";
import { s3, Bucket } from "./storage.mjs";
for (const Key of ["temporary/export.txt", "archive/export.txt", "retained/handbook.txt"]) await s3.send(new DeleteObjectCommand({ Bucket, Key }));
const objects = await s3.send(new ListObjectsV2Command({ Bucket }));
const uploads = await s3.send(new ListMultipartUploadsCommand({ Bucket }));
console.log("Objects:", objects.Contents || []);
console.log("Incomplete uploads:", uploads.Uploads || []);
JS
node --env-file=.env.s3 empty.mjs
Exija arrays vazios de objetos e de uploads incompletos. Se você criou uma sessão multipart durante a experimentação, use a operação de cancelamento do laboratório anterior com a chave pertencente a você e o upload ID exatos. Em seguida, repita estas listagens somente de leitura. Nunca ignore silenciosamente falhas nas solicitações de listagem.
Remover o bucket vazio e sua política
Nesta etapa, você excluirá o bucket pertencente a você depois que a verificação de objetos e uploads for aprovada. A política faz parte da configuração do bucket e desaparece junto com ele.
npx wrangler r2 bucket delete "$BUCKET" --env-file=.env.management
npx wrangler r2 bucket list --env-file=.env.management
Confirme o nome gerado exato. Exija que esse nome esteja ausente de uma listagem autenticada bem-sucedida. Execute a verificação de exclusão da plataforma antes de revogar a credencial de gerenciamento.
Revogar a credencial do laboratório e sair
Nesta etapa, você encerrará os acessos deixados por este exercício. Na página R2 API Tokens, revogue somente o token de objetos nomeado para este laboratório. Na página de tokens de API do seu perfil, revogue o token de gerenciamento do R2 separado que você criou para este laboratório. Excluir um bucket não revoga um token, e o logout do Wrangler não revoga credenciais do S3.
Depois da revogação, remova o arquivo local de credenciais e faça logout desta VM:
rm .env.s3 .env.management
npx wrangler logout
Inspecione a identidade estruturada. O status diferente de zero é esperado quando você está desconectado:
npx wrangler whoami --json || true
Exija loggedIn: false; mantenha o login comum do Dashboard. A plataforma verifica a remoção das credenciais locais e o logout do Wrangler. As duas revogações de tokens são pontos de verificação manuais no Dashboard neste laboratório; elas não são inferidas pela exclusão dos arquivos.
Resumo
Aplique regras de expiração por escopo, futuras transições de armazenamento e limpeza de uploads multipart, inspecione os metadados atuais, preserve os dados retidos e faça a limpeza explicitamente.



