Como Corrigir Erros de CORS (e Porque Acontecem)
Um erro de CORS significa que a sua página web tentou ler uma resposta de uma origem diferente (outro domínio, porta ou protocolo), e esse servidor não enviou cabeçalhos a dizer que isso é permitido. Os navegadores bloqueiam a resposta para proteger os utilizadores. A correção faz-se no servidor, devolvendo um cabeçalho Access-Control-Allow-Origin para a origem do seu site e tratando os pedidos de preflight OPTIONS; ou evita-se o erro enviando o pedido através do seu próprio backend na mesma origem.
É um dos erros mais confusos no desenvolvimento web porque o pedido muitas vezes chega bem ao servidor. Este guia explica o que se passa e como corrigir cada variante.
O que significa "origem"
Uma origem é a combinação de protocolo, domínio e porta:
| URL | Origem |
|---|---|
https://minhaapp.com/dashboard | https://minhaapp.com |
https://api.minhaapp.com/users | https://api.minhaapp.com (subdomínio diferente, por isso origem diferente) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (porta diferente, por isso origem diferente) |
Os navegadores seguem a política de mesma origem: o JavaScript de uma página pode ler livremente as respostas da sua própria origem, mas não das outras. O CORS (Cross-Origin Resource Sharing) é o sistema que permite a um servidor optar por aceitar: "as respostas minhas podem ser lidas por páginas destas origens".
Duas consequências surpreendem as pessoas:
- O pedido muitas vezes chega ao servidor. O CORS normalmente impede o seu código de ler a resposta, e não impede o servidor de receber o pedido. Um POST pode ter sido guardado mesmo que tenha visto um erro.
- Só os navegadores o aplicam. O curl, o Postman e o código do lado do servidor ignoram completamente o CORS. Por isso, "funciona no Postman" não lhe diz nada sobre CORS.
Passo 1: leia o erro exato
Abra as ferramentas de programador (clique com o botão direito → Inspecionar), vá à Consola e leia a mensagem completa. A formulação do Chrome indica-lhe qual é o problema:
| A mensagem contém | O que está errado |
|---|---|
No 'Access-Control-Allow-Origin' header is present | O servidor não enviou o cabeçalho, ou o pedido falhou antes de chegar ao seu código CORS (por exemplo, um 404 ou 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | O servidor permite uma origem diferente da sua |
Response to preflight request doesn't pass access control check | O preflight OPTIONS falhou |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Está a enviar cookies, e o servidor respondeu com * |
Request header field authorization is not allowed | O servidor não incluiu esse cabeçalho em Access-Control-Allow-Headers |
Depois, abra o separador Rede, encontre o pedido que falhou (e qualquer pedido OPTIONS anterior) e veja o seu código de estado e os cabeçalhos da resposta.
Verifique primeiro o código de estado. Muitos "erros de CORS" são, na realidade, um erro do servidor disfarçado. Se o servidor falhar ou devolver um 404, a resposta de erro muitas vezes não tem os cabeçalhos CORS, por isso o navegador reporta CORS em vez do problema real. Corrija o 500 ou o 404, e o erro de CORS pode desaparecer.
Passo 2: decida se deve mesmo chamar essa API a partir do navegador
Antes de acrescentar cabeçalhos, pergunte: o navegador deve chamar esta API diretamente?
- Uma API de terceiros que precisa de uma chave secreta (OpenAI, chave secreta da Stripe, a maioria dos serviços de email) nunca deve ser chamada a partir do navegador. A chave ficaria visível para todos os visitantes. Chame-a a partir do seu backend, e o problema de CORS desaparece, porque os pedidos entre servidores não estão sujeitos a CORS. Veja como manter as chaves de API seguras.
- Uma API de terceiros que não controla e que não envia cabeçalhos CORS não pode ser corrigida do seu lado. Chame-a a partir do seu backend.
- A sua própria API pode ser corrigida configurando-a corretamente. Continue abaixo.
Passo 3: corrija no seu servidor
O servidor tem de acrescentar os cabeçalhos corretos às respostas, incluindo as respostas de erro.
Para o pedido real, envie:
Access-Control-Allow-Origin: https://minhaapp.com(a origem exata do seu frontend, sem barra final)Vary: Origin, se o valor depender da origem que pediu
Para o pedido de preflight OPTIONS, responda com um estado de sucesso (200 ou 204) e:
Access-Control-Allow-Origin: https://minhaapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(cada cabeçalho personalizado que envia)- Opcionalmente
Access-Control-Max-Age: 600, para que o navegador guarde o preflight em cache durante algum tempo
A maioria das frameworks tem um pacote ou uma definição que faz isto. No Express, o pacote cors; no FastAPI, CORSMiddleware; no ASP.NET Core, AddCors; no Spring, @CrossOrigin ou uma configuração de CORS. Uma configuração típica do Express:
import cors from "cors";
app.use(cors({
origin: ["https://minhaapp.com", "http://localhost:5173"],
credentials: true,
}));
Coloque o tratamento de CORS antes das suas rotas e da autenticação, para que os pedidos de preflight (que não levam login) não sejam rejeitados com um 401.
Com um construtor com IA, descreva a configuração com precisão:
O frontend em
https://minhaapp.comchama a API emhttps://api.minhaapp.come recebe "Response to preflight request doesn't pass access control check". Configure o CORS na API para permitir exatamentehttps://minhaapp.come a origem da pré-visualização, permitir GET, POST, PATCH, DELETE com os cabeçalhos Content-Type e Authorization, tratar OPTIONS antes da autenticação, e incluir também os cabeçalhos CORS nas respostas de erro.
Passo 4: trate de cookies e credenciais
Se o seu frontend envia cookies (por exemplo, uma sessão de início de sessão) para outra origem, os dois lados têm de estar de acordo:
- O frontend define
credentials: "include"nofetch, ouwithCredentials: trueno axios. - O servidor envia
Access-Control-Allow-Credentials: true. - O
Access-Control-Allow-Origindo servidor tem de ser a origem exata, e não*.
Os cookies entre sites também precisam de SameSite=None; Secure no cookie, e alguns navegadores restringem ainda mais os cookies de terceiros. É mais uma razão para preferir a abordagem do Passo 5.
Passo 5: evite o CORS com uma configuração de mesma origem
Muitas vezes, a correção mais limpa é não fazer pedidos entre origens. Sirva a API a partir da mesma origem da página, por exemplo em https://minhaapp.com/api/...:
- Em desenvolvimento, a maioria dos servidores de desenvolvimento consegue fazer proxy. A definição
server.proxydo Vite pode encaminhar/apipara o seu backend noutra porta, para que o navegador fale sempre com uma só origem. - Em produção, encaminhe
/apipara o backend através das definições de reescrita ou proxy do seu alojamento, ou sirva o frontend e a API a partir de um único servidor.
O frontend chama então um caminho relativo como fetch("/api/orders"). Não há pedido entre origens, nem preflight entre origens, nem dores de cabeça com cookies. Significa também que não precisa de definir fixamente um domínio de API que seja diferente entre a pré-visualização e a produção.
Altere o frontend para chamar o backend com caminhos relativos /api em vez de um URL completo, e configure um proxy de desenvolvimento para que /api seja encaminhado para o servidor da API. Depois remova as definições de CORS que já não são necessárias.
O que não fazer
mode: "no-cors"nofetch. Não contorna nada; dá ao seu código uma resposta vazia e ilegível.- Extensões do navegador que desativam o CORS. Alteram apenas o seu navegador. Todos os visitantes continuam a ver o erro.
- Serviços públicos de "proxy CORS" para apps reais. Podem ler e alterar tudo o que passa por eles, e ficam indisponíveis.
Access-Control-Allow-Origin: *numa API que usa início de sessão. De qualquer forma, não funciona com credenciais, e é o padrão errado para dados privados.- Refletir de volta qualquer cabeçalho
Origincom credenciais permitidas. Isso permite que qualquer site faça pedidos autenticados em nome dos seus utilizadores. Use uma lista de permissões.
Causas comuns em apps criadas com IA
| Situação | Correção |
|---|---|
| O frontend chama uma API de terceiros com uma chave secreta | Mova a chamada para o backend |
| Funciona na pré-visualização, falha no domínio publicado | Acrescente as origens publicada e do domínio personalizado à lista de permissões, ou use caminhos relativos /api |
| Erro apenas em POST, PUT ou DELETE | Preflight não tratado; acrescente o tratamento de OPTIONS e os cabeçalhos permitidos |
| O erro apareceu depois de acrescentar o início de sessão | As credenciais exigem uma origem exata e Allow-Credentials |
| "Erro de CORS", mas o separador Rede mostra 500 | Corrija primeiro o erro do servidor |
URL da API fixo em localhost | Use caminhos relativos ou uma definição por ambiente |
CORS na Mythex
Quando um projeto Mythex tem um site e um servidor de API, ambos correm como serviços no mesmo projeto, e pode alternar entre eles na pré-visualização. Pedir ao agente que o frontend chame o backend através de um caminho relativo /api, com proxy em desenvolvimento, evita a maioria dos problemas de CORS. Se precisar mesmo de chamadas entre origens, dê ao agente o erro exato da consola e as origens envolvidas. Verifique o resultado também na app publicada, porque o endereço é diferente do da pré-visualização. Veja Apps com múltiplos serviços e Backends de API na documentação, e os nossos guias sobre como depurar uma app criada com IA e frontend vs backend.
Lista de verificação do CORS
- Leu o erro completo da consola e o código de estado do pedido que falhou
- Descartou um 404 ou 500 escondido
- APIs com chave secreta chamadas a partir do backend, e não do navegador
- O servidor envia
Access-Control-Allow-Origincom as origens permitidas exatas - O preflight
OPTIONSrespondido com os métodos e cabeçalhos permitidos, antes da autenticação - Cabeçalhos CORS presentes nas respostas de erro
- Credenciais: origem exata,
Allow-Credentials: true, definições de cookies corretas - Origens da pré-visualização, publicada e do domínio personalizado cobertas, ou caminhos relativos
/apiusados - Sem atalhos
no-cors, proxies públicos ou reflexo de qualquer origem
Perguntas
O que significa um erro de CORS?
A sua página, carregada a partir de uma origem, tentou ler uma resposta de outra origem, e a resposta desse servidor não incluía os cabeçalhos que o permitem. O navegador impede o seu código de ler a resposta. A correção está no servidor, ou na forma como o pedido é encaminhado, e não no código do frontend.
Consigo corrigir um erro de CORS a partir do frontend?
Não de forma adequada. Definições como mode: 'no-cors' apenas escondem a resposta do seu código. Corrige-se fazendo com que o servidor envie o cabeçalho Access-Control-Allow-Origin correto, ou chamando a API a partir do seu próprio backend ou de um proxy de mesma origem.
Access-Control-Allow-Origin: * é seguro?
É aceitável para dados públicos que qualquer pessoa pode ler, como uma API pública sem início de sessão. Não pode ser usado com cookies ou outras credenciais, e para APIs privadas deve listar as origens exatas que são permitidas.
Porque é que o meu pedido funciona no Postman ou no curl, mas não no navegador?
O CORS é aplicado apenas pelos navegadores. Ferramentas como o Postman e o curl não o aplicam, por isso um pedido pode ser bem-sucedido aí e ainda assim ser bloqueado quando o JavaScript da página o faz.
O que é um pedido de preflight?
Para pedidos que não são simples, como um POST com JSON ou um com um cabeçalho Authorization, o navegador envia primeiro um pedido OPTIONS a perguntar ao servidor que métodos e cabeçalhos são permitidos. Se esse pedido OPTIONS falhar ou não tiver os cabeçalhos certos, o pedido real nunca é enviado.