🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Como corrigir falha na solicitação de opções de comprovação CORS na produção

⏱️5 min read  ·  938 words

Sua API funciona em desenvolvimento, mas falha em produção comA solicitação de comprovação do CORS não passa na verificação de controle de acesso ou a solicitação OPTIONS retorna 404/405. Falhas de comprovação são um problema comum de CORS somente em produção. Veja como diagnosticá-los e corrigi-los.

O que é uma solicitação de comprovação?

Para solicitações “não simples” (PUT, DELETE, cabeçalhos personalizados ou tipo de conteúdo JSON), o navegador envia umOPÇÕES request first — o “preflight” — para perguntar ao servidor se a solicitação real é permitida. Se a simulação falhar, a solicitação real nunca será executada. As falhas de comprovação geralmente aparecem apenas na produção devido a diferentes configurações do servidor.

# Browser automatically sends this before your POST:
OPTIONS /api/users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

# Server MUST respond with matching CORS headers and 2xx status

Causa 1: o servidor não controla OPÇÕES

// 🐛 Express route only handles POST, not OPTIONS preflight
app.post('/api/users', createUser);
// The OPTIONS preflight hits no handler → 404/405 → preflight fails

// ✅ Use the cors middleware which handles OPTIONS automatically
const cors = require('cors');
app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
}));
// cors() responds to preflight OPTIONS requests before your routes

Causa 2: OPÇÕES de faixas ou blocos de proxy reverso

# nginx — explicitly handle OPTIONS preflight
location /api/ {
    # Handle preflight
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' 'https://app.example.com' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Access-Control-Max-Age' 86400 always;
        add_header 'Content-Length' 0;
        return 204;   # respond to preflight with 204 No Content
    }

    proxy_pass http://localhost:3000;
    add_header 'Access-Control-Allow-Origin' 'https://app.example.com' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
}

Causa 3: Origem do curinga com credenciais

// 🐛 Wildcard origin CANNOT be used with credentials
app.use(cors({
  origin: '*',              // ❌ fails when credentials: true
  credentials: true,
}));
// Browser error: "Access-Control-Allow-Origin cannot be '*' when
// credentials mode is 'include'"

// ✅ Specify the exact origin
app.use(cors({
  origin: 'https://app.example.com',   // exact origin, not *
  credentials: true,
}));

// ✅ For multiple origins, echo the matching one
const allowed = ['https://app.example.com', 'https://admin.example.com'];
app.use(cors({
  origin: (origin, cb) => {
    if (!origin || allowed.includes(origin)) cb(null, true);
    else cb(new Error('Not allowed by CORS'));
  },
  credentials: true,
}));

Causa 4: Cabeçalhos permitidos ausentes

// The preflight lists headers the real request will send.
// The server must allow ALL of them, or preflight fails.

// 🐛 Real request sends Authorization but server doesn't allow it
allowedHeaders: ['Content-Type'],   // missing Authorization

// ✅ Allow every custom header your client sends
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-API-Key'],

// Check the browser's preflight to see what's requested:
// Access-Control-Request-Headers: authorization, content-type
// The server's Access-Control-Allow-Headers must include all of these

Causa 5: O middleware de autenticação é executado antes do CORS

// 🐛 Auth middleware rejects the OPTIONS preflight (no auth header on preflight!)
app.use(authenticate);   // blocks OPTIONS with 401
app.use(cors());

// ✅ CORS must come BEFORE auth so preflight passes
app.use(cors({ origin: 'https://app.example.com', credentials: true }));
app.use(authenticate);   // preflight already handled by cors()
// Preflight OPTIONS requests carry no credentials by design —
// they must not be blocked by auth

Depurando falhas de comprovação

# Simulate the preflight with curl to see the server response
curl -X OPTIONS https://api.example.com/users \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Content-Type, Authorization" \
  -i

# Check the response has:
# HTTP/1.1 204 (or 200)  ← must be 2xx
# Access-Control-Allow-Origin: https://app.example.com  ← matches
# Access-Control-Allow-Methods: ...POST...  ← includes your method
# Access-Control-Allow-Headers: ...content-type, authorization...

Perguntas Frequentes

P: Por que funciona no desenvolvimento, mas falha na produção?
R: O desenvolvimento geralmente usa um proxy (Vite/CRA) que evita totalmente o CORS ou uma configuração dev CORS permissiva. A produção tem um proxy reverso real (nginx) e uma configuração mais rígida onde o tratamento de comprovação deve ser explícito.

P: Por que minha solicitação OPTIONS retorna 401?
R: Seu middleware de autenticação está sendo executado antes do CORS e rejeitando a simulação (que não carrega credenciais por design). Coloque o middleware CORS antes da autenticação para que as solicitações de simulação passem.

P: Qual código de status a simulação deve retornar?
R: 204 (sem conteúdo) ou 200. Qualquer 2xx funciona. Um 404, 405 ou 401 significa que a simulação falhou e o navegador bloqueia a solicitação real.

P: Defino cabeçalhos CORS no nginx ou no aplicativo – não em ambos?
R: Escolha um lugar. DuplicarAccess-Control-Allow-Origin cabeçalhos (do nginx e do Express) fazem com que o navegador rejeite a resposta. Use nginx OU o aplicativo, não ambos.

P: Como posso permitir credenciais (cookies) de origem cruzada?
R: DefinirAccess-Control-Allow-Credentials: true E especifique uma origem exata (não*) no servidor e usecredentials: 'include' na busca do cliente. Todos os três são necessários juntos.

Conclusão

As falhas de comprovação do CORS na produção geralmente vêm de: o servidor não manipula OPTIONS, um proxy reverso bloqueando-o, origem curinga com credenciais, falta de cabeçalhos permitidos ou middleware de autenticação rejeitando a comprovação. As correções:use ocors middleware (ou manipulação explícita de OPTIONS nginx), especifique origens exatas ao usar credenciais, permita todos os cabeçalhos que seu cliente envia e coloque CORS antes do middleware de autenticação. Depure com umcurl -X OPTIONS solicitação para ver exatamente o que o servidor retorna — a simulação deve responder 2xx com cabeçalhos CORS correspondentes.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা