Truques para depurar problemas de CORS em desenvolvimento local

1. Entendendo o Erro CORS: Sintomas e Causas Raiz

CORS (Cross-Origin Resource Sharing) é um mecanismo de segurança implementado pelos navegadores que restringe requisições HTTP entre diferentes origens. Uma origem é definida pela combinação de protocolo, domínio e porta. Por exemplo, http://localhost:3000 e http://localhost:5000 são origens diferentes.

Quando você vê o erro clássico no console:

Access to fetch at 'http://localhost:5000/api/data' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present

Isso significa que o servidor backend não incluiu o header necessário na resposta. Existem dois tipos principais de requisições CORS:

  • Requisições simples: GET, HEAD, POST com content-type específicos. O navegador envia a requisição e verifica os headers na resposta.
  • Requisições preflight: Quando usamos métodos como PUT/DELETE, headers customizados ou content-type application/json, o navegador primeiro envia uma requisição OPTIONS para verificar permissões.

2. Configurando Headers CORS Manualmente no Backend

A forma mais básica de resolver CORS é adicionar headers manualmente na resposta do servidor. Exemplo em Node.js puro:

// Servidor HTTP básico com headers CORS
const http = require('http');

const server = http.createServer((req, res) => {
  // Headers CORS manuais
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');

  // Responder requisições preflight
  if (req.method === 'OPTIONS') {
    res.writeHead(204);
    res.end();
    return;
  }

  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ message: 'Dados liberados' }));
});

server.listen(5000);

Para desenvolvimento, usar Access-Control-Allow-Origin: * é aceitável, mas lembre-se de restringir em produção.

3. Usando Middlewares e Configurações Específicas por Framework

Express.js (Node.js)

// Instalação: npm install cors
const express = require('express');
const cors = require('cors');
const app = express();

// CORS global para desenvolvimento
app.use(cors({
  origin: 'http://localhost:3000',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

app.get('/api/data', (req, res) => {
  res.json({ message: 'CORS configurado com Express' });
});

app.listen(5000);

FastAPI (Python)

# Instalação: pip install fastapi uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/api/data")
async def get_data():
    return {"message": "CORS configurado com FastAPI"}

Hono.js (Bun)

import { Hono } from 'hono'
import { cors } from 'hono/cors'

const app = new Hono()

app.use('/*', cors({
  origin: 'http://localhost:3000',
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization']
}))

app.get('/api/data', (c) => {
  return c.json({ message: 'CORS configurado com Hono' })
})

export default app

4. Depurando com Ferramentas de Rede e Extensões do Navegador

O painel Network do DevTools é seu melhor amigo para depurar CORS:

  1. Abra o DevTools (F12) e vá para a aba "Network"
  2. Recarregue a página ou dispare a requisição
  3. Filtre por "XHR" ou "Fetch" para ver requisições de API
  4. Clique na requisição com erro (geralmente em vermelho)
  5. Na aba "Headers", verifique:
  6. Request Headers: Veja se Origin está presente
  7. Response Headers: Procure por Access-Control-Allow-Origin
  8. Status Code: 200 para sucesso, 204 para OPTIONS bem-sucedido

Extensões como "CORS Unblock" podem ajudar em testes rápidos, mas lembre-se de desativá-las em produção, pois elas desabilitam a segurança do navegador.

5. Simulando Cenários com Proxy Reverso Local

Uma abordagem elegante é configurar um proxy no seu servidor de desenvolvimento.

Vite (React/Vue/Svelte)

// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
}

http-proxy-middleware (Node.js)

// Instalação: npm install http-proxy-middleware
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  );
};

Testando com curl

# Teste direto sem CORS
curl -X GET http://localhost:5000/api/data -H "Origin: http://localhost:3000" -I

# Verifique se o header Access-Control-Allow-Origin aparece

6. Truques Avançados: Credenciais, Cookies e Headers Customizados

Quando você precisa enviar cookies ou autenticação, o cenário fica mais complexo:

// Backend - Express com credenciais
app.use(cors({
  origin: 'http://localhost:3000',
  credentials: true,  // Permite cookies
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID']
}));

// Frontend - Fetch com credenciais
fetch('http://localhost:5000/api/data', {
  method: 'GET',
  credentials: 'include',  // Envia cookies
  headers: {
    'Content-Type': 'application/json',
    'X-Request-ID': '12345'
  }
})

Importante: Quando credentials: true está ativo, Access-Control-Allow-Origin não pode ser *. Você deve especificar a origem exata.

7. Erros Comuns e Soluções Rápidas para Desenvolvimento Local

Mistura de HTTP e HTTPS

Se seu frontend roda em HTTPS (ex: https://localhost:3000) e o backend em HTTP (http://localhost:5000), o navegador bloqueia por segurança. Solução: use HTTP em ambos durante desenvolvimento ou configure certificados SSL locais.

Cache do Navegador

O navegador pode cachear respostas CORS antigas. Use:
- Hard Refresh: Ctrl+Shift+R (Windows/Linux) ou Cmd+Shift+R (Mac)
- Limpar Cache: DevTools > Network > Desmarcar "Disable cache" e recarregar

localhost vs 127.0.0.1

O navegador trata http://localhost:3000 e http://127.0.0.1:3000 como origens diferentes. Se seu frontend acessa localhost e o backend espera 127.0.0.1, haverá erro. Mantenha consistência.

8. Checklist Final e Automação para Evitar Dores de Cabeça

Script de inicialização com CORS aberto

// start-dev.sh
#!/bin/bash
export ALLOWED_ORIGINS="http://localhost:3000"
export NODE_ENV="development"
node server.js

Configuração de ambiente

// .env.development
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
CORS_CREDENTIALS=true

// server.js
const allowedOrigins = process.env.ALLOWED_ORIGINS.split(',');
app.use(cors({
  origin: allowedOrigins,
  credentials: process.env.CORS_CREDENTIALS === 'true'
}));

Testes automatizados com Supertest + Jest

// Instalação: npm install supertest jest --save-dev
const request = require('supertest');
const app = require('./app');

describe('CORS Headers', () => {
  test('Deve retornar Access-Control-Allow-Origin', async () => {
    const response = await request(app)
      .get('/api/data')
      .set('Origin', 'http://localhost:3000');

    expect(response.headers['access-control-allow-origin'])
      .toBe('http://localhost:3000');
  });

  test('Deve responder OPTIONS corretamente', async () => {
    const response = await request(app)
      .options('/api/data')
      .set('Origin', 'http://localhost:3000')
      .set('Access-Control-Request-Method', 'POST');

    expect(response.status).toBe(204);
    expect(response.headers['access-control-allow-methods'])
      .toContain('POST');
  });
});

Seguindo estes truques e configurações, você conseguirá depurar e resolver a maioria dos problemas de CORS em desenvolvimento local. Lembre-se: CORS é uma preocupação apenas do navegador — ferramentas como curl e Postman ignoram essas restrições, então use-as para verificar se sua API está funcionando corretamente independentemente do CORS.

Referências

  • MDN Web Docs: CORS — Documentação completa sobre Cross-Origin Resource Sharing, incluindo exemplos de headers e cenários de erro.
  • Express.js CORS Middleware — Documentação oficial do pacote cors para Node.js, com opções de configuração detalhadas.
  • FastAPI CORS Middleware — Guia oficial de configuração de CORS no FastAPI com exemplos práticos.
  • Vite Proxy Configuration — Documentação do Vite sobre configuração de proxy para desenvolvimento, útil para contornar CORS.
  • Chrome DevTools Network Panel — Guia oficial do Google sobre como usar o painel Network para depurar requisições e headers.
  • Hono.js CORS Middleware — Documentação oficial do middleware CORS para Hono.js, framework moderno para Bun.
  • Supertest Documentation — Biblioteca para testes HTTP em Node.js, útil para validar headers CORS em testes automatizados.