Introdução: quando o navegador diz "não" e o Postman diz "sim"
Imagine a situação: você está escrevendo um frontend em JavaScript, fazendo uma requisição fetch para uma API. Em resposta — um erro vermelho no console:
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.Você segura a cabeça, abre o Postman, insere a mesma URL, clica em Enviar — e oh, milagre, os dados chegam! O servidor está funcionando? Está. Então por que o navegador bloqueia a requisição?
Essa situação é um clássico do desenvolvimento web. No Stack Overflow, essa pergunta acumulou milhares de visualizações. Hoje vamos olhar por baixo dos panos e entender por que isso acontece, como funciona o CORS e como corrigir. Vamos nessa!
O que é CORS e para que serve?
CORS (Cross-Origin Resource Sharing) é um mecanismo de segurança do navegador. Ele proíbe que JavaScript de um site (por exemplo, http://localhost:3000) faça requisições para outro (por exemplo, https://api.example.com), a menos que o servidor permita explicitamente.
Por quê? Para que um invasor não possa, através do seu navegador, roubar dados de outro site. Sem CORS, qualquer script poderia ler seu e-mail, contas bancárias — um horror.
Mas há um detalhe: CORS funciona apenas no navegador. Postman, curl, requisições de servidor (Node.js, Python) — eles não verificam CORS. Essa é a primeira e principal razão pela qual o Postman funciona e o JavaScript não.
Como o CORS funciona por baixo dos panos: em palavras simples
Quando seu JavaScript (por exemplo, fetch) faz uma requisição entre domínios, o navegador faz duas coisas:
- Verifica o tipo de requisição.
- Se necessário — envia uma requisição preflight (OPTIONS).
Requisição simples vs Preflight
Existem dois tipos de requisições entre domínios:
- Requisição simples — se você usa GET, POST ou HEAD, e os cabeçalhos são apenas básicos (Content-Type: text/plain, application/x-www-form-urlencoded, multipart/form-data). O navegador envia a requisição e verifica o cabeçalho de resposta
Access-Control-Allow-Origin. - Requisição Preflight — se você usa cabeçalhos não padrão (por exemplo,
Authorization), métodos PUT/DELETE, ou Content-Type: application/json. O navegador primeiro envia uma requisição OPTIONS para perguntar: "Posso fazer essa requisição?"
Aqui está um exemplo de preflight no código:
fetch('https://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json', // Isso causa preflight 'Authorization': 'Bearer my-token' }, body: JSON.stringify({ key: 'value' })}).then(response => response.json()).then(data => console.log(data)).catch(err => console.error('CORS error:', err));Se o servidor não responder ao OPTIONS com o cabeçalho correto Access-Control-Allow-Origin — o navegador bloqueia a requisição principal.
Por que o Postman ignora o CORS?
Postman não é um navegador. Ele não usa a política de mesma origem (Same-Origin Policy). Ele simplesmente envia uma requisição HTTP e recebe a resposta. Não importa de onde veio a requisição — ele não verifica cabeçalhos CORS. O servidor pode retornar qualquer coisa, o Postman mostrará a resposta.
Portanto, quando você testa a API pelo Postman, você vê que o servidor está funcionando. Mas o navegador exige que o servidor permita explicitamente o acesso a partir do seu domínio.
Como corrigir o erro CORS: 3 maneiras reais
1. Configurar o servidor (o caminho correto)
Se você tem acesso ao servidor, adicione o cabeçalho Access-Control-Allow-Origin. Por exemplo, no Node.js com Express:
const express = require('express');const app = ex