Servir uma Central de Ajuda com Ativos Estáticos

CloudflareBeginner
Pratique Agora

Introdução

Uma central de ajuda combina ativos estáticos—HTML, CSS, imagens ou JavaScript do navegador prontos—com respostas geradas pelo código da aplicação. O Cloudflare pode fornecer esses arquivos junto com um Worker, o que é útil para manter um site pequeno e sua API juntos. Você explorará qual deles processa uma requisição primeiro, depois fará as requisições de integridade chegarem à API e exigirá uma credencial antes de fornecer um documento sintético da equipe.

Este laboratório independente começa em /home/labex/project/help-center com Node.js 22.22.0, Wrangler 4.131.1 instalado localmente no projeto e arquivos HTML/CSS/JavaScript fornecidos. Use sua própria conta de aprendizado do Cloudflare e os conhecimentos de autorização, implantação e arquivos de segredos ensinados anteriormente. Não é necessário ter uma VM anterior, recurso de nuvem, domínio comprado, banco de dados ou upgrade pago. As requisições contam para o uso normal da conta.

Todo o conteúdo e as credenciais são sintéticos. Mantenha um terminal aberto. A configuração insegura permanecerá local; somente o Worker corrigido será implantado. Exclua a implantação, remova a credencial de teste local e saia da conta antes de encerrar a VM.

Observar o Roteamento com Prioridade para Ativos Localmente

Nesta etapa, você examinará a estrutura fornecida da central de ajuda e observará como, por padrão, os arquivos correspondentes têm prioridade sobre um Worker. Os arquivos de teste incluem um arquivo /api/health conflitante de propósito e um manual fictício da equipe. Tudo é sintético, e esta primeira configuração permanecerá local.

cd /home/labex/project/help-center
node --version
npx wrangler --version
ls -R public

Espere ver Node v22.22.0 e Wrangler 4.131.1. A configuração instalou as ferramentas locais do projeto; ao reproduzi-la em outro local, use npm ci com o arquivo de lock do projeto. O diretório público contém HTML, CSS, JavaScript do navegador e os dois arquivos de teste de roteamento. Não coloque credenciais nem documentos internos reais nele.

WORKER_NAME="labex-help-$(openssl rand -hex 6)"
cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "workers_dev": true,
  "preview_urls": false,
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "html_handling": "none",
    "not_found_handling": "none",
    "run_worker_first": false
  }
}
CONFIG

HTML fornece a estrutura da página, CSS controla sua aparência e o JavaScript do navegador chama a API de integridade. Portanto, uma página pode parecer correta mesmo quando essa API está com problemas. Precedência do roteamento significa decidir se um arquivo correspondente ou o seu handler terá a primeira oportunidade de responder a uma requisição.

directory seleciona os arquivos a serem enviados, enquanto binding os disponibiliza para o handler como env.ASSETS. html_handling: none mantém os caminhos de arquivo explícitos; not_found_handling: none evita retornar automaticamente a página inicial de um aplicativo de página única para um caminho desconhecido. Este laboratório precisa que as rotas desconhecidas permaneçam claramente distintas. O handler mapeia explicitamente / para /index.html, porque o tratamento automático de HTML está desativado. Ele pretende retornar JSON para a verificação de integridade e encaminhar os demais caminhos para o armazenamento de ativos.

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    if (new URL(request.url).pathname === '/api/health') {
      return Response.json({status: 'ok', service: 'help-center'});
    }
    const assetUrl = new URL(request.url);
    if (assetUrl.pathname === '/') assetUrl.pathname = '/index.html';
    return env.ASSETS.fetch(new Request(assetUrl, request));
  }
};
JS
npx wrangler dev --ip 0.0.0.0 --port 8080 > dev.log 2>&1 &
cat dev.log

Aguarde o log informar que o servidor está pronto antes de continuar; repita cat se necessário.

curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/styles.css
curl -i http://127.0.0.1:8080/api/health
curl -i http://127.0.0.1:8080/staff/handbook.html

A página inicial e o CSS retornam 200. A verificação de integridade retorna o texto estático STATIC_HEALTH_PLACEHOLDER, e não o JSON do handler, porque o ativo correspondente ganha a prioridade. O manual sintético também pode ser lido diretamente. Isso demonstra a precedência do roteamento, não uma implantação segura. Não implante esta configuração inicial. Use a verificação antes de alterá-la.

Se o laboratório disponibilizar uma prévia Web 8080, abra-a agora. A estrutura da central de ajuda será carregada, mas a linha de status informará que o status da API está indisponível, porque o navegador esperava JSON. Mantenha as respostas da CLI como verificações oficiais do roteamento; use a prévia como uma confirmação visual.

O exemplo abaixo mostra o problema inicial: a página e a folha de estilos carregam, mas API status unavailable significa que o navegador não recebeu o JSON de integridade esperado. Uma estrutura de página carregada, sozinha, não confirma que o roteamento da API funciona.

Central de ajuda antes da correção do roteamento, com API status unavailable

Executar o Worker Antes dos Ativos e Proteger o Conteúdo da Equipe

Nesta etapa, você fará o handler decidir quais requisições podem receber arquivos. Executá-lo primeiro permite que a API retorne JSON e que a rota da equipe verifique uma credencial antes de buscar um documento. Os arquivos públicos ainda devem carregar normalmente. Pare o processo de desenvolvimento indicado por jobs; o exemplo pressupõe o trabalho 1.

jobs
kill %1
cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "workers_dev": true,
  "preview_urls": false,
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "html_handling": "none",
    "not_found_handling": "none",
    "run_worker_first": true
  }
}
CONFIG

Com run_worker_first: true, toda requisição entra no handler, inclusive aquelas que, de outra forma, corresponderiam diretamente a um arquivo. Também existem padrões de rota seletivos, mas este pequeno aplicativo usa uma única política de roteamento explícita. Consulte Configuração de ativos estáticos.

Gere uma credencial descartável para a equipe usando o fluxo de trabalho com arquivo de segredo ensinado anteriormente. umask restringe as permissões de novos arquivos. Este é um token de portador usado somente no laboratório, nunca um token de API da conta. Mantenha-o fora de arquivos públicos, do JavaScript do navegador, de URLs e de logs.

umask 077
STAFF_TOKEN=$(openssl rand -hex 24)
printf 'STAFF_TOKEN=%s\n' "$STAFF_TOKEN" > .dev.vars
cat .gitignore

Confirme que .dev.vars* e .env* estão sendo ignorados. Substitua o handler pela política completa abaixo. Ela decodifica o caminho uma vez, fornece a integridade como JSON, permite somente os arquivos públicos listados, verifica a credencial da equipe antes de buscar esse ativo e rejeita caminhos desconhecidos. A requisição enviada a ASSETS não contém o cabeçalho Authorization do cliente. As respostas protegidas usam private, no-store.

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    let path;
    try { path = decodeURIComponent(url.pathname); }
    catch { return Response.json({error: 'not_found'}, {status: 404}); }
    if (path === '/api/health') {
      if (request.method !== 'GET') {
        return Response.json({error: 'method_not_allowed'}, {status: 405, headers: {Allow: 'GET'}});
      }
      return Response.json({status: 'ok', service: 'help-center'});
    }
    const publicPaths = ['/', '/index.html', '/styles.css', '/app.js'];
    if (path === '/staff/handbook.html') {
      if (!env.STAFF_TOKEN) return Response.json({error: 'staff_unconfigured'}, {status: 503});
      if (request.headers.get('Authorization') !== `Bearer ${env.STAFF_TOKEN}`) {
        return Response.json({error: 'unauthorized'}, {status: 401});
      }
    } else if (!publicPaths.includes(path)) {
      return Response.json({error: 'not_found'}, {status: 404});
    }
    if (!['GET', 'HEAD'].includes(request.method)) {
      return Response.json({error: 'method_not_allowed'}, {status: 405, headers: {Allow: 'GET, HEAD'}});
    }
    url.pathname = path === '/' ? '/index.html' : path;
    // Only known paths reach the asset store, after any required authorization.
    const response = await env.ASSETS.fetch(new Request(url, {method: request.method}));
    if (path === '/staff/handbook.html') {
      const headers = new Headers(response.headers);
      headers.set('Cache-Control', 'private, no-store');
      return new Response(response.body, {status: response.status, headers});
    }
    return response;
  }
};
JS
npx wrangler dev --ip 0.0.0.0 --port 8080 > dev.log 2>&1 &
cat dev.log

Depois que o servidor estiver pronto, compare as respostas públicas, protegidas e desconhecidas:

curl -i http://127.0.0.1:8080/api/health
curl -i http://127.0.0.1:8080/staff/handbook.html
curl -i http://127.0.0.1:8080/staff/handbook.html -H "Authorization: Bearer wrong-token"
curl -i http://127.0.0.1:8080/staff/handbook.html -H "Authorization: Bearer $STAFF_TOKEN"
curl -i --path-as-is http://127.0.0.1:8080/%73taff/handbook.html
curl -i http://127.0.0.1:8080/missing-page -H "Sec-Fetch-Mode: navigate"

Agora, a verificação de integridade retorna 200 {"status":"ok","service":"help-center"}, embora o arquivo conflitante ainda exista. Credenciais ausentes ou incorretas retornam JSON 401; o token correspondente retorna o HTML do manual sintético. O caminho codificado da equipe também retorna 401, e a navegação para um caminho desconhecido retorna JSON 404. Remover o arquivo de teste esconderia o problema de roteamento; mantenha-o.

Atualize a prévia Web 8080 opcional: o status agora deve informar API status: ok. O endpoint do manual retorna JSON 401 sem uma credencial. Alguns navegadores incorporados bloqueiam a navegação para essa resposta e deixam a página anterior visível; use o resultado do curl acima para inspecioná-la. Esse comportamento do navegador não comprova acesso bem-sucedido. Use o curl com o cabeçalho sintético para acessar o conteúdo autorizado; não cole o segredo na barra de endereços. Faça a verificação com o servidor em execução. Ela também verifica HEAD, caminhos codificados, grafias alternativas e tipos de ativos públicos.

Compare a linha de status com a prévia anterior. API status: ok mostra agora que a página consegue ler a resposta de integridade. Essa verificação visual cobre a rota pública de integridade; use as respostas do curl acima para avaliar o manual protegido.

Central de ajuda depois da correção do roteamento, com API status ok

Implantar os Ativos e o Handler Protegido

Nesta etapa, você implantará somente a configuração corrigida na sua conta de aprendizado. Pare o processo local atual usando o número real exibido por jobs.

jobs
kill %1
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_tail:read

Conclua o link e o código do dispositivo exibidos no navegador em que você iniciou a sessão, revise as permissões existentes do Wrangler e o Background Access e selecione sua conta de aprendizado. Aguarde a conclusão no terminal.

npx wrangler whoami --json

Confirme o nome e o ID reais da conta e substitua YOUR_ACCOUNT_ID abaixo por esse ID. Mantenha o nome do recurso original e as configurações corrigidas dos ativos.

cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "account_id": "YOUR_ACCOUNT_ID",
  "workers_dev": true,
  "preview_urls": false,
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "html_handling": "none",
    "not_found_handling": "none",
    "run_worker_first": true
  }
}
CONFIG
npx wrangler deploy

O Wrangler envia o diretório público e implanta o handler. Copie abaixo a URL exata de workers.dev exibida. Reutilize o subdomínio existente da conta de aprendizado; quem estiver usando o serviço pela primeira vez pode seguir o prompt de subdomínio disponível do Wrangler.

APP_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$APP_URL/staff/handbook.html"

Antes do envio do segredo, essa rota retorna 503 staff_unconfigured: o handler é executado primeiro e falha de forma segura. .dev.vars é uma configuração local e não foi enviado pela implantação. Se a propagação inicial do hostname atrasar uma resposta, tente novamente brevemente antes de investigar um erro persistente.

npx wrangler secret bulk .dev.vars
npx wrangler secret list

Confirme que STAFF_TOKEN está listado como secret_text, sem exibir seu valor. A implantação do segredo pode levar pouco tempo para chegar a todos os locais de atendimento. Se as próximas requisições ainda retornarem staff_unconfigured, aguarde 10 segundos e repita essas requisições por até dois minutos. Exija um 401 estável sem a credencial e um 200 com ela antes de usar a verificação. Uma divergência persistente precisa ser investigada; não aceite 503 como resultado final nem altere a política de autorização para fazer uma verificação passar.

curl -i "$APP_URL/"
curl -i "$APP_URL/api/health"
curl -i "$APP_URL/staff/handbook.html"
curl -i "$APP_URL/staff/handbook.html" -H "Authorization: Bearer $STAFF_TOKEN"
curl -i "$APP_URL/missing-page" -H "Sec-Fetch-Mode: navigate"

Espere receber HTML público, JSON de integridade, 401 sem a credencial, HTML do manual com a credencial e 404 para a página desconhecida. Na mesma conta do Dashboard, abra Compute → Workers & Pages, localize o Worker exato e confirme sua URL pública. Use a verificação para confirmar a propriedade real, os bindings implantados, o conteúdo dos ativos e o comportamento da autorização. Você também pode abrir a página inicial pública no seu próprio navegador; não envie o token da equipe por uma URL. A barreira de token sintético é uma lição de roteamento, não um sistema completo de identidade da equipe.

Na guia Overview do Worker, compare o nome no breadcrumb e o endereço workers.dev vinculado com a saída da implantação. O nome e o subdomínio nesta captura de tela são exemplos; o nome gerado e o subdomínio da sua conta serão diferentes. Este é o endereço público implantado, enquanto o Web 8080 mostra o servidor local de desenvolvimento. Abrir este Worker existente não exige criar outro aplicativo.

Worker da central de ajuda implantado e seu endereço público em Overview

Excluir a Implantação da Central de Ajuda

Nesta etapa, você removerá o Worker do laboratório, os ativos associados e o binding do segredo enquanto ainda estiver autorizado. Confirme o nome exclusivo e a conta:

cat wrangler.jsonc
npx wrangler delete

Verifique o nome exato do laboratório no prompt e pressione a única tecla y. O Wrangler 4.131.1 pode informar o erro documentado de autenticação do KV do Workers Sites legado depois da exclusão. Não amplie as permissões nem use essa mensagem como evidência de exclusão. Atualize Workers & Pages e use a verificação: um inventário autorizado bem-sucedido deve mostrar que esse nome está ausente. Preserve os recursos não relacionados, a conta e o subdomínio workers.dev.

Remover a Credencial Local e Desconectar

Nesta etapa, você removerá a credencial sintética local depois de verificar a limpeza na nuvem e, em seguida, desconectará esta VM.

rm .dev.vars
unset STAFF_TOKEN
npx wrangler logout
npx wrangler whoami --json

Espere ver "loggedIn": false explicitamente; uma saída de status não zero indicando falta de autenticação é esperada quando esse resultado estruturado estiver presente. Use a verificação e encerre a VM. O login no navegador pode continuar disponível; nem encerrar a VM nem sair da conta exclui recursos da nuvem por você.

Resumo

Você observou o roteamento com prioridade para ativos e, em seguida, usou o tratamento com prioridade para o Worker para manter as respostas da API e a autorização à frente dos arquivos correspondentes. A estrutura fornecida da central de ajuda manteve o HTML, o CSS e o JavaScript do navegador públicos, enquanto o tratamento explícito de caminhos bloqueou requisições não autenticadas à equipe e rotas desconhecidas. Você testou caminhos codificados e navegação no estilo do navegador, implantou o site corrigido com um envio separado do segredo e depois verificou a exclusão e a saída da conta.

Escolha deliberadamente a ordem de roteamento sempre que arquivos estáticos e políticas da aplicação compartilharem um hostname. Uma resposta local, sozinha, não comprova a configuração implantada nem a identidade da conta.