CORS: O Erro Que Todo Desenvolvedor Já Viu
Você está construindo um frontend que chama sua API. Funciona no Postman. Funciona com curl. Mas o navegador diz:
Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.Isso não é um erro do servidor. É o navegador protegendo o usuário.
O Que CORS Realmente É
CORS (Cross-Origin Resource Sharing) é um mecanismo de segurança do navegador. Por padrão, JavaScript rodando na origem A não pode fazer requisições para a origem B. Uma origem é a combinação de protocolo + domínio + porta:
| URL | Origem |
|---|---|
http://localhost:3000 | http://localhost:3000 |
https://meuapp.com | https://meuapp.com |
https://api.meuapp.com | https://api.meuapp.com (subdomínio diferente = origem diferente) |
https://meuapp.com:8080 | https://meuapp.com:8080 (porta diferente = origem diferente) |
Como Funciona
Para requisições simples (GET, POST com content types padrão), o navegador envia a requisição normalmente mas verifica os headers da resposta. Se a resposta não incluir Access-Control-Allow-Origin, o navegador bloqueia o JavaScript de ler a resposta.
Para requisições complexas (PUT, DELETE, headers customizados, content type JSON), o navegador envia uma requisição preflight primeiro:
OPTIONS /api/data HTTP/1.1
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, AuthorizationO servidor deve responder com:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400Resolvendo CORS
Express.js:
import cors from 'cors';
// Permitir todas as origens (apenas desenvolvimento!)
app.use(cors());
// Produção: especificar origens permitidas
app.use(cors({
origin: ['https://meuapp.com', 'https://staging.meuapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // se usar cookies
}));API routes Next.js:
export async function GET(request: Request) {
const data = await getData();
return Response.json(data, {
headers: {
'Access-Control-Allow-Origin': 'https://meuapp.com',
'Access-Control-Allow-Methods': 'GET, POST',
},
});
}Nginx:
location /api/ {
add_header 'Access-Control-Allow-Origin' 'https://meuapp.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
}Erros Comuns
- Usar
*com credentials.Access-Control-Allow-Origin: *não funciona comcredentials: true. Você deve especificar a origem exata. - Esquecer o handler de OPTIONS. Seu servidor deve responder a requisições preflight OPTIONS com headers CORS e status 204.
- Resolver no frontend. CORS é configuração server-side. Nenhum código frontend pode contornar (esse é o objetivo).
- Proxy no dev, esquecer em prod. Rewrites do
next.config.jsfuncionam em desenvolvimento mas não em produção. Você precisa de headers CORS reais no servidor da API.
Alternativas ao CORS
- Proxy same-origin: Roteie chamadas de API pelo seu próprio servidor (
/api/proxy) para o navegador ver requisições same-origin. - Server-side rendering: Busque dados no servidor (Next.js Server Components), não no navegador. Sem necessidade de CORS.
Debug seus headers: Referência HTTP — verifique status codes e headers das suas respostas de API.