Resumo Executivo (TL;DR):
Se o seu servidor Express, Nginx ou Cloud Run responde com HTML quando um robô solicita /robots.txt ou /sitemap.xml, seu portal está sofrendo de Colisão SPA Catch-All. Esse é o bug silencioso responsável por derrubar a visibilidade orgânica de centenas de startups que migram para stacks modernas de JavaScript.


1. O Bug Mais Comum da Web Moderna

Ao desenvolver aplicações em React, Vue ou Vite servidas por um backend Express, é prática comum adicionar um fallback no final do roteador para que as rotas internas funcionem:

// Código problemático encontrado em milhares de repositórios:
app.use(express.static('public'));

// ROTA CATCH-ALL PERIGOSA:
app.get('*', (req, res) => {
  res.sendFile(path.resolve('public', 'index.html'));
});

À primeira vista, tudo funciona: o usuário clica em /dashboard e a SPA renderiza perfeitamente.

Mas o que acontece quando o Googlebot ou o GPTBot faz uma requisição para:
GET /robots.txt ou GET /sitemap.xml?

Se o arquivo não existir exatamente no caminho esperado pelo middleware estático, o Express cai na rota catch-all e retorna index.html com status HTTP 200 OK!


2. As Consequências Técnicas da Colisão

  1. Falha na RFC 9309: O robô espera um documento de texto puro estruturado em linhas de diretivas. Em vez disso, recebe <!DOCTYPE html><html lang="pt-BR">....
  2. Ignorância do Sitemap: O indexador tenta ler tags XML (<urlset>) e encontra tags HTML (<div id="root">), abortando a ingestão de todo o mapa do site.
  3. Desperdício Extremo de Crawl Budget: O bot gasta tempo tentando interpretar JavaScript em arquivos que deveriam ser texto plano de 500 bytes.

3. A Solução Arquitetural no Express

Para blindar o servidor contra colisão de SPA, rotas essenciais devem ser registradas explicitamente antes do fallback e com o cabeçalho correto:

// 1. Rota canônica explícita com Content-Type RFC 9309 garantido:
app.get("/robots.txt", (_req: Request, res: Response) => {
  const robotsPath = path.join(publicDir, "robots.txt");
  res.setHeader("Content-Type", "text/plain; charset=utf-8");
  return res.sendFile(robotsPath);
});

// 2. Rota canônica para sitemaps com Content-Type XML:
app.get("/sitemap.xml", (_req: Request, res: Response) => {
  res.setHeader("Content-Type", "application/xml; charset=utf-8");
  return res.sendFile(path.join(publicDir, "sitemap.xml"));
});

// 3. APENAS NO FINAL: Fallback SPA para navegação humana
app.get("*", (_req: Request, res: Response) => {
  res.sendFile(path.join(publicDir, "index.html"));
});

4. Como o EngineGuard Detecta e Previne Colisões

O BAASBOSS EngineGuard inclui um canário de teste de colisão SPA:

  • Ele dispara requisições HTTP para /robots.txt, /sitemap.xml e /llms.txt.
  • Inspeciona se o primeiro caractere retornado contém <!DOCTYPE ou <html.
  • Se detectar colisão, emite alerta crítico de Nível 1 e pontuação zero na categoria protocol.

Garanta que sua infraestrutura esteja livre de colisões silenciosas com o BAASBOSS EngineGuard.

❓ Perguntas Frequentes (FAQ)
O que é uma colisão de SPA Catch-All? +
É quando uma regra global como app.get('*', ...) captura requisições destinadas a arquivos estáticos (como robots.txt ou sitemap.xml) e responde com o index.html da SPA em vez do arquivo puro.
Por que o Googlebot penaliza sites com colisão de SPA? +
Porque ao ler um sitemap ou robots.txt que contém HTML, o parser do Googlebot falha na leitura das regras e pode considerar todas as diretivas de rastreamento corrompidas.
Como testar se o meu site tem colisão de SPA? +
Execute curl -i https://seudominio.com/robots.txt no terminal e verifique se o Content-Type retornado é text/plain. Se retornar text/html com tags , há colisão.
GUARDIÃO DE INFRAESTRUTURA & PARIDADE

Seu software está invisível para ChatGPT, Perplexity e Claude por Drift de Catálogo?

O BAASBOSS EngineGuard audita conformidade RFC 9309, reconcilia o Triângulo Dourado (llms.txt ↔ Sitemaps ↔ Schema.org) e auto-remedia descompassos com 1-click.

Conhecer o EngineGuard ➔
TAGS: #SPA Catch-All #Express.js #Cloud Run #Robots.txt #SEO Técnico