O Pesadelo de Debugging HTTP/HTTPS: Uma Jornada de 24 Horas pelo Inferno do Mixed Content
Passei 24 horas tentando entender por que meu app React continuava fazendo requisições HTTP a partir de páginas HTTPS — mesmo com meu código convertendo isso. A causa me chocou.
---
Atualização (novembro de 2025): O STRAŦUM já está no ar em Alpha Privado! A plataforma de marketing com 9 agentes mencionada neste post está aceitando testadores iniciais. Solicite acesso em stratum.chandlernguyen.com ou leia a história completa do lançamento.
---
Contexto: A Jornada da Plataforma de Marketing Continua
Lembra daquele post de setembro onde eu disse que estava acelerando uma plataforma de marketing com 10 agentes enquanto tirava cochilos? Quatro semanas depois, tinha 3 agentes funcionando e mirando outubro/novembro para o lançamento do alpha.
Bom, já é fim de outubro. Hora de uma atualização.
As Boas Notícias:
- A plataforma finalmente tem um nome: STRAŦUM (Intelligence Over Execution)
- Diretrizes completas de marca e sistema de design (acontece que branding demora mais que codar)
- 9 dos 10 agentes construídos e integrados
- Arquitetura multi-tenant realmente funcionando
- Fase final: se preparando para testes pré-alpha, somente por convite
A Realidade:
Fiquei doente por 10 dias depois de 8 dias de folga (a vida acontece, né?). Isso pausou tudo e atrasou meu cronograma. Adeus ao lançamento em outubro, certo?
Mas aqui está a coisa sobre desenvolvimento solo: você controla o ritmo. Sem pressão para lançar quando não está pronto. Sem investidores no seu pescoço. Só... construa direito.
Este post é sobre um desses momentos "construa direito" que virou uma maratona de debugging de 6 horas. Porque exatamente quando eu estava voltando a todo vapor depois de ficar doente, minha plataforma de deploy decidiu ter outros planos.
Quando a AWS Cai, Engenheiros Ficam Criativos (e Às Vezes Se Arrependem)
Tem uma coisa que eles não ensinam nos bootcamps de programação: às vezes sua plataforma de deploy simplesmente... desaparece. Não por causa de algo que você fez errado, mas porque a AWS decidiu ter uma interrupção generalizada afetando deployments do Vercel globalmente.
Foi assim que minha segunda-feira começou. Meu site em produção estava fora, o Vercel mostrava erros, e eu tive exatamente um pensamento: "Preciso de um backup. Rápido."
Entre o Cloudflare Pages. Eu tinha ouvido coisas boas. Ótimo CDN, deployments automáticos, configuração simples. O que poderia dar errado?
Narrador: Tudo. Tudo poderia dar errado.
A Migração Que Pareceu Fácil Demais
A migração para o Cloudflare Pages foi surpreendentemente tranquila. Conectei meu repositório GitHub, configurei as variáveis de ambiente no painel, fiz push para o main. Três minutos depois: deployado.
"Nossa," pensei. "Isso é quase fácil demais."
Aí abri o site em produção.
```
Mixed Content: The page at 'https://my-site.com/...' was loaded over HTTPS,
but requested an insecure resource 'http://stratum-api.us-central1.run.app/...'
```
Aquela sensação de afundamento quando você percebe que sua comemoração foi prematura? É, exatamente isso.
O Problema: Chamadas HTTP de uma Página HTTPS
Meu app React estava fazendo requisições HTTP para minha API backend enquanto a página em si estava carregada via HTTPS. Browsers (com razão) bloqueiam isso como um risco de segurança. Erros de Mixed Content. Cada chamada de API estava falhando.
"Mas espera," me disse, "eu tenho ensureHttpsInProduction() no meu código! É para converter HTTP para HTTPS automaticamente!"
Verifiquei o bundle deployado. A função estava lá. A lógica estava correta. O console do browser mostrava a conversão acontecendo. Então por que requisições HTTP ainda passavam?
Primeira Tentativa de Debugging: A Caça às Variáveis de Ambiente
Talvez as variáveis de ambiente no Cloudflare não estivessem sendo captadas?
```bash
# Verificado no Cloudflare Dashboard
VITE_API_URL=https://stratum-api.us-central1.run.app ✓
VITE_SUPABASE_URL=https://your-project.supabase.co ✓
```
Tudo HTTPS. Tudo correto.
Disparei um rebuild. Esperei. Deployou. Abri o site.
Mesmo erro. Ainda requisições HTTP.
Segunda Tentativa: O Grande Reimport
Talvez os arquivos não estivessem usando o API_BASE_URL centralizado?
Passei a próxima hora atualizando 24 arquivos para importar de @/lib/api em vez de usar diretamente import.meta.env.VITE_API_URL. Cada componente que fazia chamadas de API recebeu o tratamento.
```typescript
// Antes
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/v1/...`);
// Depois
import \{ API_BASE_URL \} from '@/lib/api';
const response = await fetch(`$\{API_BASE_URL\}/api/v1/...`);
```
Push. Deploy. Esperei.
Ainda quebrado.
Nesse ponto, começo a questionar minhas escolhas de vida.
A Reviravolta: Arquivos Faltando no Git
Mas espera, piora.
Enquanto investigava por que meu enforcement de HTTPS não estava funcionando, descobri algo aterrorizante. O arquivo api.ts contendo ensureHttpsInProduction() nem estava no meu repositório Git.
Tampouco o authService.ts. Nem o csvSanitizer.ts. Três arquivos críticos de frontend, simplesmente... faltando.
Como? O arquivo .gitignore tinha isso:
```
# Python stuff
lib/
build/
dist/
```
Parece razoável para Python, certo? Exceto que meus utilitários de frontend viviam em apps/web/src/lib/. O padrão amplo lib/ estava acidentalmente ignorando todo o meu diretório lib de frontend!
Isso significava:
1. O Cloudflare estava fazendo build a partir do repositório (sem esses arquivos)
2. Meu desenvolvimento local tinha esses arquivos (funcionando bem localmente)
3. Eu não tinha IDEIA que eles não estavam sendo rastreados
O fix:
```diff
# .gitignore - Antes
-lib/
# .gitignore - Depois
+apps/api/lib/ # Específico para Python
+!apps/web/src/lib/ # Incluir explicitamente o lib do frontend
```
Adicionei os arquivos que faltavam, fiz commit, push. Agora o Cloudflare tinha o código de enforcement HTTPS!
Exceto... os erros HTTP continuaram.
Terceira Tentativa: Validação no Momento do Build
Nesse ponto, questiono tudo. "Sabe o que?" pensei. "Se isso continua acontecendo, preciso PREVENIR que chegue à produção."
Escrevi um plugin Vite que falha o build se detectar URLs HTTP em produção:
```typescript
function validateProductionUrls(mode: string) \{
if (mode !== 'production') return;
const apiUrl = process.env.VITE_API_URL || '';
if (apiUrl && apiUrl.trim().startsWith('http://')) {
if (!apiUrl.includes('localhost') && !apiUrl.includes('127.0.0.1')) {
throw new Error(
`❌ HTTPS ENFORCEMENT FAILED
Environment Variable: VITE_API_URL
Current Value: ${apiUrl\}
This will cause Mixed Content errors in production!`
);
}
}
}
```
Genial, né? Agora é IMPOSSÍVEL fazer deploy com URLs HTTP.
Deployei de novo. Build passou (as variáveis de ambiente eram HTTPS). O site carregou.
Mesmo. Maldito. Erro.
O Momento de Clareza: Arquivos Locais Estavam Sendo Deployados
Tarde (muito tarde) da noite, tive uma percepção.
Verifiquei o bundle JavaScript deployado de novo. Dessa vez, olhei de verdade. A URL dentro era:
```javascript
"http://stratum-api.us-central1.run.app"
```
Mas minhas variáveis de ambiente do Cloudflare eram HTTPS. Então de onde vinha essa URL HTTP?
Aí caiu a ficha. Meu arquivo .env.production local.
```bash
# apps/web/.env.production (ARQUIVO LOCAL)
VITE_API_URL=http://stratum-api.us-central1.run.app
```
O Cloudflare Pages estava deployando meu arquivo de ambiente local em vez de usar as variáveis do painel!
Verifiquei o .cloudflare-pages-ignore:
```
# Environment files
.env
.env.local
.env.development
.env.test
# .env.production ← FALTANDO!
```
Mão. Na. Cara.
O Fix: Uma Linha
```diff
# apps/web/.cloudflare-pages-ignore
.env
.env.local
.env.development
.env.test
+.env.production
```
Deployei. Esperei.
Um erro diferente dessa vez! Progresso!
```
Access to fetch at 'https://stratum-api.us-central1.run.app/...'
from origin 'https://preview-xyz.stratum-marketing-suite.pages.dev'
has been blocked by CORS policy
```
Erros de CORS! Lindos, lindos erros de CORS! Isso significava que o HTTPS estava funcionando!
Mas Espera, Tem Mais: A Conspiração do Cache
Corrigi o CORS. Deployei de novo. Abri meu domínio personalizado.
Erros HTTP de novo.
O quê?!
Acontece que o CDN do Cloudflare estava fazendo cache agressivo do bundle antigo. O novo deployment (com HTTPS) estava no ar na URL de preview, mas meu domínio personalizado estava servindo conteúdo em cache com URLs HTTP.
Limpar o cache do Cloudflare requer:
1. Encontrar as configurações de zona certas (não no painel do Pages)
2. Navegar pelas configurações de domínio (nada óbvio)
3. Limpar o cache manualmente (a cada deployment)
Depois de horas depurando problemas de HTTP/HTTPS, tomei uma decisão.
O Retorno ao Vercel: Às Vezes Chato é Melhor
A AWS tinha voltado. O Vercel estava funcionando de novo.
Migrei tudo de volta para o Vercel. Por quê?
1. Invalidação automática de cache — Sem necessidade de limpeza manual
2. Gestão mais simples de variáveis de ambiente — O que você define é o que você tem
3. Debugging mais rápido — Menos infraestrutura para raciocinar
4. Testado em batalha — Conheço suas peculiaridades
O deployment no Vercel levou 3 minutos. Sem erros HTTP. Sem problemas de cache. Simplesmente... funcionou.
O Que Aprendi (Do Jeito Difícil)
1. Sempre Ignore .env.production nas Plataformas de Deploy
```
# .vercelignore
# .cloudflare-pages-ignore
# .netlify-ignore
.env
.env.local
.env.development
.env.test
.env.production ← NÃO ESQUEÇA ESSE
```
2. Padrões Amplos no .gitignore São Perigosos em Monorepos
```diff
# ❌ Ruim - Ignora pastas lib do frontend E do backend
-lib/
-build/
-dist/
# ✅ Bom - Específico para cada contexto
+apps/api/lib/ # Específico para Python
+apps/api/build/
+apps/api/dist/
+apps/web/dist/ # Apenas output do Vite
```
Sempre pergunte: "Esse padrão poderia acidentalmente ignorar algo importante?"
Em um monorepo com múltiplas linguagens (Python + TypeScript), padrões amplos destinados a um ecossistema podem acidentalmente ignorar arquivos críticos em outro.
3. Validação no Momento do Build Ainda Vale a Pena
Mesmo que não tenha detectado o problema do arquivo local, a validação no build previne *futuras* configurações erradas:
```typescript
// vite.config.ts
export default defineConfig((\{ mode \}) => \{
validateProductionUrls(mode);
return {
// ... config
\};
});
```
4. Defesa em Múltiplas Camadas Funciona
Nossa arquitetura final tem TRÊS camadas:
- No build: Falha o build se URLs HTTP forem detectadas
- Em runtime: Converte HTTP → HTTPS se a página for carregada via HTTPS
- No deployment: Exclui arquivos .env locais
5. URLs de Preview São Suas Amigas
Sempre teste na URL de preview primeiro. Se funcionar lá mas não no seu domínio personalizado, provavelmente é cache.
6. Conheça as Peculiaridades da Sua Plataforma
- Vercel: Simples, invalida cache automaticamente, variáveis de ambiente "simplesmente funcionam"
- Cloudflare Pages: Ótimo CDN, mas limpeza manual de cache e configuração mais complexa
O Código Que Me Salvou
Aqui está a função final ensureHttpsInProduction():
```typescript
function ensureHttpsInProduction(url: string): string \{
// Converte apenas no contexto do browser quando o site é carregado via HTTPS
if (typeof window !== 'undefined' && window.location.protocol === 'https:') {
// Não converte URLs de localhost/127.0.0.1 (desenvolvimento local)
if (url.startsWith('http://') &&
!url.includes('localhost') &&
!url.includes('127.0.0.1')) {
console.warn('[API] Converting HTTP to HTTPS:', url);
return url.replace('http://', 'https://');
\}
}
return url;
}
```
E a validação no momento do build em vite.config.ts:
```typescript
function validateProductionUrls(mode: string) \{
if (mode !== 'production') return;
const apiUrl = process.env.VITE_API_URL || '';
// Verifica por HTTP (deveria ser HTTPS)
if (apiUrl && apiUrl.trim().startsWith('http://')) {
if (!apiUrl.includes('localhost') && !apiUrl.includes('127.0.0.1')) {
throw new Error(`
❌ HTTPS ENFORCEMENT FAILED
Environment Variable: VITE_API_URL
Current Value: ${apiUrl\}
Mixed Content Error Prevention:
Browsers block HTTP requests from HTTPS pages.
Fix: Update environment variables to use HTTPS URLs.
`);
}
}
}
```
A Lição Real: Debugging é Trabalho de Detetive
Esse não foi um problema de código. Foi uma expedição de arqueologia de configuração.
Os bugs reais foram:
1. ✅ Padrões amplos no .gitignore ignorando arquivos críticos de frontend
2. ✅ .env.production faltando no .cloudflare-pages-ignore
3. ✅ Cache agressivo do CDN mascarando o fix
4. ✅ Assumindo precedência de variáveis de ambiente
A solução técnica foi uma linha em um arquivo .ignore.
O debugging? Isso levou 6 horas, 14 deployments, e café em quantidade absurda.
Valeu a Pena?
Com certeza. Aqui está o que ganhei:
1. Compreensão profunda das políticas de segurança de Mixed Content
2. Validação no momento do build que previne problemas futuros
3. Enforcement de HTTPS em múltiplas camadas que é agnóstico a plataformas
4. Apreciação genuína pela simplicidade do Vercel
E o mais importante: uma ótima história de debugging para compartilhar. :P
O Git Log Conta a História
```bash
2033b9a fix: add .env.production to .vercelignore
3555390 docs: migrate deployment documentation from Cloudflare Pages to Vercel
a4edb09 chore: force clean Cloudflare Pages rebuild
590c271 fix: enhance ensureHttpsInProduction logging
15d69c6 chore: force rebuild of UserProfile bundle
a1c345f fix: add .env.production to cloudflare-pages-ignore ← O FIX DO .ENV
635d80d docs: update documentation for Cloudflare Pages migration
edfa611 feat: add build-time HTTPS enforcement
802c1e9 fix: enforce HTTPS for all API calls across frontend
26f6b87 refactor: comprehensive .gitignore audit and cleanup
3758a9c fix: unignore frontend lib directory and add missing files ← O FIX DO GITIGNORE
```
Cada commit representa uma hora de debugging no mundo antigo, mas com o Claude Code, graças a Deus, minha velocidade foi maior. Uma hipótese testada. Uma lição aprendida.
Para Outros Engenheiros Lutando Contra Erros de Mixed Content
Se você está lendo isso porque está depurando o mesmo problema, aqui está seu checklist:
1. Verifique Suas Variáveis de Ambiente:
```bash
# Print os valores reais sendo usados
console.log('API URL:', import.meta.env.VITE_API_URL);
```
2. Verifique Seu Bundle Deployado:
```bash
# Baixe e pesquise o bundle JavaScript
curl https://your-site.com/assets/index-ABC123.js | grep "http://"
```
3. Verifique Seus Arquivos Ignore:
```bash
# Certifique-se de que .env.production está excluído
cat .vercelignore
cat .cloudflare-pages-ignore
cat .netlify-ignore
```
4. Verifique Seu .gitignore (Monorepos):
```bash
# Certifique-se de que arquivos críticos não estão sendo ignorados
git ls-files apps/web/src/lib/ # Deve mostrar api.ts, etc.
# Se vazio, verifique padrões amplos
grep "^lib/" .gitignore # ❌ Amplo demais
grep "^apps/api/lib/" .gitignore # ✅ Específico
```
5. Verifique Seu Cache:
```bash
# Teste na URL de preview primeiro
# Se o preview funcionar mas a produção não = problema de cache
```
6. Adicione Validação no Momento do Build:
```typescript
// Previna que aconteça de novo
if (mode === 'production' && url.startsWith('http://')) \{
throw new Error('HTTPS required in production!');
\}
```
O Checklist de Migração Que Eu Queria Ter Tido
Ao trocar de plataformas de deploy:
- [ ] Liste TODAS as variáveis de ambiente da plataforma antiga
- [ ] Configure variáveis de ambiente na nova plataforma PRIMEIRO
- [ ] Adicione TODOS os arquivos .env ao .ignore (incluindo .env.production)
- [ ] Verifique se o .gitignore não está ignorando arquivos críticos (execute git ls-files para checar)
- [ ] Teste na URL de preview antes do domínio personalizado
- [ ] Verifique o bundle deployado por URLs HTTP
- [ ] Verifique as configurações de CORS se o backend for separado
- [ ] Documente as peculiaridades específicas da plataforma
Ainda Codando, Ainda Aprendendo, Ainda Quebrando Coisas (Às Vezes)
Seis horas de debugging para um fix de uma linha. Isso é engenharia de software em resumo.
O código que lançamos é importante, claro. Mas as habilidades de debugging que desenvolvemos? Essas são o que nos tornam engenheiros melhores.
Da próxima vez que minha plataforma de deploy cair (e vai acontecer), estarei pronto. Tenho:
- ✅ Enforcement de HTTPS agnóstico a plataformas
- ✅ Validação no momento do build
- ✅ Melhor compreensão da precedência de variáveis de ambiente
- ✅ Uma estratégia de deployment de backup
E com sorte, este post vai economizar para alguém algumas dessas 6 horas. :)
Você já teve um "fix de uma linha" que demorou um tempo embaraçosamente longo para encontrar? Adoraria ouvir suas histórias de detetive no debugging — na desgraça, a companhia ajuda!
Abraços,
Chandler





