Introdução
Quando um site de documentação move páginas, os links antigos ainda devem levar os visitantes ao lugar certo. Um redirecionamento é uma resposta HTTP que informa ao navegador para solicitar uma URL diferente. Neste laboratório, o KV armazenará um pequeno catálogo que associa caminhos antigos a novos caminhos de documentação.
Você inspecionará e validará um conjunto de dados JSON fornecido antes de importá-lo e, em seguida, lerá o catálogo em várias páginas. Paginação significa solicitar um lote limitado de resultados e usar um marcador de continuação para buscar o lote seguinte. Por fim, você alterará um destino e aposentará duas entradas, preservando um registro não relacionado no mesmo namespace. Isso é útil sempre que você mantém uma coleção de configurações em vez de editar uma chave por vez.
Conclua primeiro os laboratórios guiados anteriores sobre KV. Esta VM nova tem Node.js 22.22.0 e o Wrangler 4.131.1 local do projeto em /home/labex/project/redirect-catalog. A configuração inicial fornece cinco redirecionamentos sintéticos, mas não os importa nem cria recursos na nuvem. Use sua própria conta de aprendizado com as mesmas permissões de leitura da conta, gravação de Worker e gravação do KV. Um Worker e um namespace descartáveis são suficientes; não é necessário fazer upgrade pago nem comprar um domínio para este pequeno conjunto de dados. O catálogo público contém apenas caminhos de exemplo.
Conectar um namespace de redirecionamentos
Nesta etapa, você conectará um namespace independente para um pequeno catálogo de redirecionamentos. O binding ROUTES identificará esse namespace tanto para as operações na linha de comando quanto para o Worker. Cada laboratório começa com seus próprios recursos, portanto o catálogo não afetará nenhum namespace anterior.
Entre no projeto preparado:
cd /home/labex/project/redirect-catalog
Gere um nome exclusivo uma única vez. openssl rand -hex 6 imprime um sufixo aleatório; $(...) insere esse sufixo no nome. A variável do shell mantém esse nome disponível para os comandos seguintes neste terminal.
WORKER_NAME="labex-routes-$(openssl rand -hex 6)"
printf '%s\n' "$WORKER_NAME"
Autorize esta VM. Além de ler a identidade da sua conta, Workers Scripts Write permite fazer deploy e excluir recursos, e Workers KV Write permite gerenciar o namespace e as chaves deste laboratório.
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_kv:write
Abra no navegador o link de dispositivo exibido, informe o código atual, revise as permissões solicitadas e a conta de aprendizado e autorize o Wrangler. O acesso em segundo plano também pode aparecer na página de consentimento. Volte ao terminal e aguarde a conclusão do login.
Revise as mesmas permissões de gravação do Worker e do KV apresentadas em Create a Feature Flag Store. Confirme a conta de aprendizado antes de autorizar.
npx wrangler whoami --json
Confirme loggedIn: true e o name da conta de aprendizado, mesmo que apenas uma conta esteja listada. Copie o id dessa conta. Salve-o na configuração abaixo, substituindo YOUR_ACCOUNT_ID antes de executar o comando. O here-document do cat grava em um arquivo tudo o que estiver entre as duas linhas JSON; > substitui o arquivo. O delimitador sem aspas permite que o shell insira $WORKER_NAME.
cat > wrangler.jsonc <<JSON
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-07-30",
"account_id": "YOUR_ACCOUNT_ID",
"workers_dev": true
}
JSON
Crie um namespace nessa conta. O título dele compartilha o nome exclusivo do Worker, para que você possa reconhecer os dois mais tarde. --update-config=false deixa a edição do binding visível para você, em vez de alterar o arquivo automaticamente.
npx wrangler kv namespace create "$WORKER_NAME-routes" --update-config=false
A saída inclui o ID do novo namespace. Copie-o e substitua YOUR_ACCOUNT_ID e YOUR_NAMESPACE_ID nesta configuração completa. O nome do binding ROUTES é escolhido para o seu código; o ID identifica o recurso real da Cloudflare.
cat > wrangler.jsonc <<JSON
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-07-30",
"account_id": "YOUR_ACCOUNT_ID",
"workers_dev": true,
"kv_namespaces": [
{ "binding": "ROUTES", "id": "YOUR_NAMESPACE_ID" }
]
}
JSON
npx wrangler kv namespace list
Encontre o título do namespace deste laboratório e compare o ID dele com o ID no arquivo. Outros namespaces podem estar presentes; não os altere. Essa configuração registra qual conta e qual recurso os próximos comandos deverão usar. Um binding é uma referência a um namespace, não uma cópia dos dados dele.
Validar e importar um pequeno catálogo
Nesta etapa, você verificará um conjunto de dados antes que um comando grave todas as entradas. Uma operação em massa evita trabalho repetitivo, mas também repete qualquer erro nos dados fornecidos. Comece lendo o arquivo preparado:
cat redirects.json
Cada objeto tem uma key, como route:/old-start, e um value, como /docs/start. O prefixo route: agrupa os registros do catálogo; ele faz parte da chave, não é um diretório. O destino é um caminho neste mesmo site, não uma URL externa arbitrária.
Escreva um script comum de validação em Node.js. Ele lê um nome de arquivo, verifica o array e os campos, rejeita chaves duplicadas e imprime uma contagem somente depois que todas as entradas são aprovadas. O Set registra as chaves já encontradas. As expressões regulares limitam este conjunto de dados didático a caminhos antigos simples e destinos de documentação; essas são regras desta aplicação, não restrições impostas pelo KV.
cat > validate-redirects.mjs <<'JS'
import { readFile } from "node:fs/promises";
const filename = process.argv[2] ?? "redirects.json";
const entries = JSON.parse(await readFile(filename, "utf8"));
if (!Array.isArray(entries) || entries.length === 0 || entries.length > 20) {
throw new Error("Use a non-empty teaching dataset of at most 20 entries.");
}
const seen = new Set();
for (const entry of entries) {
if (!entry || typeof entry.key !== "string" || !/^route:\/old-[a-z-]+$/.test(entry.key)) {
throw new Error("Every key must name an old route, such as route:/old-start.");
}
if (typeof entry.value !== "string" || !/^\/docs\/[a-z-]+$/.test(entry.value)) {
throw new Error("Every destination must be a /docs/ path on this site.");
}
if (Object.keys(entry).some(key => !["key", "value"].includes(key))) {
throw new Error("This dataset accepts only key and value fields.");
}
if (seen.has(entry.key)) throw new Error(`Duplicate key: ${entry.key}`);
seen.add(entry.key);
}
console.log(`Validated ${entries.length} unique redirect entries.`);
JS
node validate-redirects.mjs redirects.json
Espere Validated 5 unique redirect entries.. Se a validação falhar, corrija o arquivo antes de importá-lo. Rejeitar chaves duplicadas é importante porque gravar a mesma chave novamente substitui o valor dela.
Primeiro, crie localmente um registro auxiliar que não seja uma rota e depois importe o catálogo. Esse registro ajudará você a verificar se a manutenção posterior do catálogo preserva outros dados.
npx wrangler kv key put system:owner labex-redirect-demo --binding ROUTES --local
npx wrangler kv bulk put redirects.json --binding ROUTES --local
npx wrangler kv key list --binding ROUTES --local
Espere cinco entradas route: e mais system:owner. bulk put grava as entradas do arquivo; ele não substitui o namespace inteiro nem remove as chaves que não estão no arquivo. Ele também não promete uma alteração atômica visível em todos os lugares ao mesmo tempo.
Agora importe o mesmo conjunto de dados revisado no namespace de nuvem deste laboratório:
npx wrangler kv key put system:owner labex-redirect-demo --binding ROUTES --remote
npx wrangler kv bulk put redirects.json --binding ROUTES --remote
npx wrangler kv key list --binding ROUTES --remote
Confirme as seis chaves. As opções de destino explícitas mantêm separadas a prática local e as gravações na nuvem. Execute a verificação desta etapa antes de alterar qualquer entrada.
Ler todas as páginas e fornecer redirecionamentos
Nesta etapa, você criará um Worker que lista todas as chaves de rotas e fornece seus redirecionamentos. Uma única chamada list() do KV pode retornar apenas parte de uma coleção. O cursor é um marcador de continuação fornecido pelo KV; passe-o de volta sem alterações para solicitar a parte seguinte.
Escreva este handler. O limit: 2, propositalmente pequeno, torna a paginação visível com apenas cinco registros. Em código de produção, normalmente você usaria um tamanho de página maior; este laboratório limita os dados a vinte entradas para manter o loop pequeno.
cat > src/index.js <<'JS'
export default {
async fetch(request, env) {
const url = new URL(request.url);
try {
if (url.pathname === "/catalog") {
const names = [];
let cursor;
let complete = false;
let pages = 0;
do {
const page = await env.ROUTES.list({ prefix: "route:", limit: 2, cursor });
names.push(...page.keys.map(key => key.name));
pages += 1;
complete = page.list_complete;
cursor = complete ? undefined : page.cursor;
if ((!complete && !cursor) || pages > 20) {
return Response.json({ error: "Catalog could not be completed" }, { status: 503 });
}
} while (!complete);
return Response.json({ keys: names, pages });
}
if (url.pathname.startsWith("/docs/")) {
return new Response(`Example destination: ${url.pathname}`);
}
const target = await env.ROUTES.get(`route:${url.pathname}`);
if (target === null) return new Response("Not found", { status: 404 });
if (!/^\/docs\/[a-z-]+$/.test(target)) {
return Response.json({ error: "Invalid redirect destination" }, { status: 500 });
}
return Response.redirect(new URL(target, url.origin).href, 302);
} catch {
return Response.json({ error: "Redirect storage unavailable" }, { status: 503 });
}
}
};
JS
O loop do...while solicita pelo menos uma página e continua até que list_complete seja true. Ele mantém prefix: "route:" em todas as solicitações, impedindo que o registro auxiliar do proprietário entre no catálogo. names.push(...) adiciona os nomes das chaves de cada página ao resultado.
Um array keys vazio não significa necessariamente que a listagem terminou: entradas excluídas ou expiradas podem deixar uma página sem chaves retornadas enquanto ainda há mais páginas. Por isso, o loop usa list_complete, e não o tamanho do array. O limite de páginas e a verificação de um cursor ausente produzem um erro controlado se esta demonstração pequena não conseguir concluir uma listagem. Consulte Listagem e paginação do KV.
Para outros caminhos, o Worker lê a chave de rota correspondente. Rotas ausentes retornam 404; um destino compatível produz uma resposta 302 com um cabeçalho Location. O runtime verifica os destinos novamente para que um valor do KV editado incorretamente não redirecione visitantes para outro site. As respostas /docs/ são placeholders simples que mostram o caminho do destino, não um site de documentação completo.
npx wrangler dev --local --ip 0.0.0.0 --port 8080 > local.log 2>&1 &
DEV_PID=$!
cat local.log
Aguarde a mensagem de pronto e depois inspecione o catálogo completo:
curl -i http://127.0.0.1:8080/catalog
Espere cinco chaves de rota ordenadas e pelo menos três páginas. Páginas vazias adicionais são possíveis; o resultado importante é o conjunto completo de chaves, sem uma entrada system:owner.
curl -i http://127.0.0.1:8080/old-start
Espere HTTP 302 e Location: http://127.0.0.1:8080/docs/start. Por padrão, o curl mostra a resposta de redirecionamento sem segui-la. Mantenha o conjunto de dados local inalterado para comparação posterior.
Atualizar rotas selecionadas e preservar outros dados
Nesta etapa, você alterará o catálogo na nuvem sem substituir o namespace. A nova página inicial é /docs/getting-started, enquanto duas páginas temporárias não devem mais redirecionar.
npx wrangler kv key put route:/old-start /docs/getting-started --binding ROUTES --remote
A gravação de uma chave selecionada deixa as outras rotas inalteradas. Para várias exclusões, o Wrangler aceita um array JSON com os nomes exatos das chaves. Leia esta pequena lista de aposentadoria antes de executar a exclusão:
cat > retired-keys.json <<'JSON'
["route:/old-contact", "route:/old-event"]
JSON
cat retired-keys.json
npx wrangler kv bulk delete retired-keys.json --binding ROUTES --remote
Se for solicitado, confirme que o binding e a operação listada se referem ao namespace descartável deste laboratório. A lista contém somente duas chaves de rota; ela não contém system:owner.
npx wrangler kv key list --binding ROUTES --remote
npx wrangler kv key get system:owner --binding ROUTES --remote --text
Espere três rotas restantes e o valor inalterado labex-redirect-demo. Não execute novamente a importação em massa original agora: os valores antigos desfariam a atualização e restaurariam as chaves aposentadas.
Faça o deploy do Worker, confirme o binding ROUTES e copie o endereço público real:
npx wrangler deploy
WORKER_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$WORKER_URL/catalog"
Primeiro confirme que /catalog retorna HTTP 200 e as chaves JSON esperadas. Se aparecer uma página de erro do Cloudflare, aguarde um pouco e repita as solicitações somente de leitura. Uma rota removida só está correta quando retorna HTTP 404 com o corpo da aplicação Not found; o código de status sozinho não basta.
O catálogo deve conter somente route:/old-pricing, route:/old-start e route:/old-support. Teste os caminhos alterado e aposentados:
curl -i "$WORKER_URL/old-start"
curl -i "$WORKER_URL/old-contact"
curl -i "$WORKER_URL/old-event"
Espere que o caminho inicial redirecione para /docs/getting-started; os dois caminhos aposentados devem retornar 404. Se os novos dados da nuvem ainda não estiverem visíveis, aguarde a propagação do KV e repita as verificações somente de leitura. Uma falha de conexão não é um resultado de aposentadoria bem-sucedida.
curl -i http://127.0.0.1:8080/catalog
O desenvolvimento local ainda lista as cinco rotas originais. Essa diferença confirma que os comandos de manutenção foram direcionados ao armazenamento na nuvem. No Dashboard, selecione a mesma conta, abra Storage & databases → Workers KV e inspecione o namespace deste laboratório. Compare as três entradas de rota e o registro auxiliar do proprietário preservado com a saída dos comandos. Este checkpoint é somente de leitura; o nome e o ID do namespace gerados são específicos desta execução.
Selecione KV Pairs para ver os registros abaixo. Use Refresh se abriu o namespace antes de os comandos de manutenção terminarem.

Excluir os recursos descartáveis da nuvem
Nesta etapa, você removerá os dois recursos enquanto o Wrangler ainda está autorizado. Um namespace pode sobreviver ao seu Worker, portanto excluir somente a aplicação não remove os dados dela.
Pare o processo de desenvolvimento local iniciado neste terminal:
kill "$DEV_PID"
Inspecione as referências de recursos salvas antes de excluir qualquer coisa:
cat wrangler.jsonc
Confirme o nome do Worker labex-routes-... e o ID do namespace ROUTES. Exclua o Worker selecionado por esta configuração:
npx wrangler delete
Se for solicitado, verifique se o nome exibido corresponde a este laboratório e confirme com y. Em seguida, exclua somente o namespace referenciado por ROUTES:
npx wrangler kv namespace delete --binding ROUTES
Revise o namespace em qualquer solicitação de confirmação antes de aceitar. Mantenha wrangler.jsonc intacto para que a verificação independente possa identificar os recursos que devem estar ausentes.
npx wrangler kv namespace list
O namespace deste laboratório deve estar ausente; os namespaces não relacionados devem permanecer. Atualize as listas do Dashboard para confirmar que o Worker e o namespace do laboratório desapareceram. Uma solicitação com falha ou um login expirado não comprova a exclusão. Execute a verificação desta etapa antes de sair da sessão, para que ela possa inspecionar um inventário autorizado.
Encerrar a autorização da VM
Nesta etapa, você desconectará o Wrangler depois que a verificação da limpeza for aprovada. Sair da sessão encerra a autorização do Wrangler salva nesta VM; isso não exclui recursos na nuvem nem encerra a sessão do Dashboard no navegador comum.
npx wrangler logout
npx wrangler whoami --json
Confirme que o resultado estruturado informa "loggedIn": false. Este comando não autenticado pode terminar com um status de saída diferente de zero, o que é esperado aqui. Se houver apenas um erro de conexão e nenhum estado explícito de autenticação, tente novamente quando a conexão funcionar.
Os arquivos locais restantes e o estado local do KV pertencem a esta VM descartável. Eles são separados dos recursos da nuvem que você já excluiu. Agora você pode concluir o laboratório.
Resumo
Você validou um pequeno conjunto de dados de redirecionamentos antes de uma gravação em massa, manteve explícitos os destinos local e na nuvem e percorreu todas as páginas de uma listagem do KV com prefixo. Você alterou uma rota e aposentou duas chaves exatas, preservando um registro de proprietário não relacionado. As respostas do Worker implantado confirmaram o novo destino e as rotas aposentadas ausentes, enquanto o catálogo local manteve seus dados originais.
Por fim, você excluiu o Worker e o namespace descartáveis e encerrou a sessão. Em seguida, você lidará com leituras de configuração que podem retornar temporariamente uma versão anterior.



