Guias

Como corrigir erros de CORS (e por que eles 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 dizendo que isso é permitido. Os navegadores bloqueiam a resposta para proteger o usuário. Você corrige isso no servidor, retornando um cabeçalho Access-Control-Allow-Origin para a origem do seu site e tratando requisições de preflight OPTIONS, ou evita o problema enviando a requisição pelo seu próprio backend, na mesma origem.

É um dos erros mais confusos do desenvolvimento web porque, muitas vezes, a requisição chega ao servidor sem problemas. Este guia explica o que está acontecendo e como corrigir cada variante.

O que significa “origem”

Uma origem é a combinação de protocolo, domínio e porta:

URLOrigem
https://meuapp.com/dashboardhttps://meuapp.com
https://api.meuapp.com/usuarioshttps://api.meuapp.com (subdomínio diferente, portanto origem diferente)
http://localhost:5173http://localhost:5173
http://localhost:3000http://localhost:3000 (porta diferente, portanto origem diferente)

Os navegadores seguem a política de mesma origem: o JavaScript de uma página pode ler livremente as respostas da própria origem, mas não de outras. O CORS (Cross-Origin Resource Sharing) é o sistema que permite que um servidor opte por isso: “respostas minhas podem ser lidas por páginas dessas origens”.

Duas consequências surpreendem as pessoas:

  • A requisição muitas vezes chega ao servidor. O CORS normalmente impede que o seu código leia a resposta, não que o servidor receba a requisição. Um POST pode ter sido salvo mesmo que você tenha visto um erro.
  • Só os navegadores aplicam. curl, Postman e código do lado do servidor ignoram o CORS por completo. Por isso “funciona no Postman” não diz nada sobre CORS.

Passo 1: leia o erro exato

Abra as ferramentas de desenvolvedor (clique com o botão direito → Inspecionar), vá para o Console e leia a mensagem completa. A redação do Chrome indica qual é o problema:

A mensagem contémO que está errado
No 'Access-Control-Allow-Origin' header is presentO servidor não enviou o cabeçalho, ou a requisição falhou antes de chegar ao seu código de CORS (por exemplo, um 404 ou 500)
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied originO servidor permite uma origem diferente da sua
Response to preflight request doesn't pass access control checkA requisição preflight OPTIONS falhou
...must not be the wildcard '*' when the request's credentials mode is 'include'Você está enviando cookies, e o servidor respondeu com *
Request header field authorization is not allowedO servidor não listou esse cabeçalho em Access-Control-Allow-Headers

Em seguida, abra a aba Rede, encontre a requisição que falhou (e qualquer requisição OPTIONS antes dela) e veja o código de status e os cabeçalhos da resposta.

Verifique primeiro o código de status. Muitos “erros de CORS” são, na verdade, um erro do servidor disfarçado. Se o servidor quebra ou retorna um 404, a resposta de erro dele muitas vezes não tem os cabeçalhos de CORS, então o navegador informa CORS em vez do problema real. Corrija o 500 ou o 404, e o erro de CORS pode desaparecer.

Passo 2: decida se o navegador deveria chamar essa API

Antes de adicionar cabeçalhos, pergunte: o navegador deveria chamar essa API diretamente?

  • Uma API de terceiros que exige uma chave secreta (OpenAI, a chave secreta do Stripe, a maioria dos serviços de e-mail) nunca deve ser chamada pelo navegador. A chave ficaria visível para todos os visitantes. Chame-a a partir do seu backend, e o problema de CORS desaparece, porque requisições de servidor para servidor não estão sujeitas ao CORS. Veja como manter as chaves de API seguras.
  • Uma API de terceiros que você não controla e que não envia cabeçalhos de CORS não pode ser corrigida do seu lado. Chame-a pelo seu backend.
  • Sua própria API pode ser corrigida configurando-a corretamente. Continue abaixo.

Passo 3: corrija no seu servidor

O servidor precisa adicionar os cabeçalhos corretos às respostas, inclusive às respostas de erro.

Para a requisição real, envie:

  • Access-Control-Allow-Origin: https://meuapp.com (a origem exata do seu frontend, sem barra final)
  • Vary: Origin, se o valor depender da origem que fez a requisição

Para a requisição preflight OPTIONS, responda com um status de sucesso (200 ou 204) e:

  • Access-Control-Allow-Origin: https://meuapp.com
  • Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
  • Access-Control-Allow-Headers: Content-Type, Authorization (cada cabeçalho personalizado que você envia)
  • Opcionalmente Access-Control-Max-Age: 600, para que o navegador guarde o preflight em cache por um tempo

A maioria dos frameworks tem um pacote ou uma configuração que faz isso. 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 no Express:

import cors from "cors";

app.use(cors({
  origin: ["https://meuapp.com", "http://localhost:5173"],
  credentials: true,
}));

Coloque o tratamento de CORS antes das suas rotas e da autenticação, para que as requisições preflight (que não levam login) não sejam rejeitadas com um 401.

Com um criador com IA, descreva a configuração com precisão:

O frontend em https://meuapp.com chama a API em https://api.meuapp.com e recebe "Response to preflight request doesn't pass access control check". Configure o CORS na API para permitir exatamente https://meuapp.com e a origem da prévia, permitir GET, POST, PATCH, DELETE com os cabeçalhos Content-Type e Authorization, tratar OPTIONS antes da autenticação e incluir os cabeçalhos de CORS também nas respostas de erro.

Passo 4: trate cookies e credenciais

Se o seu frontend envia cookies (por exemplo, uma sessão de login) para outra origem, os dois lados precisam estar de acordo:

  • O frontend define credentials: "include" no fetch, ou withCredentials: true no axios.
  • O servidor envia Access-Control-Allow-Credentials: true.
  • O Access-Control-Allow-Origin do servidor precisa ser a origem exata, não *.

Cookies entre sites também precisam de SameSite=None; Secure, e alguns navegadores restringem ainda mais os cookies de terceiros. Isso é mais um motivo 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 requisições entre origens. Sirva a API a partir da mesma origem da página, por exemplo em https://meuapp.com/api/...:

  • Em desenvolvimento, a maioria dos servidores de desenvolvimento consegue fazer proxy. A opção server.proxy do Vite pode encaminhar /api para o seu backend em outra porta, então o navegador só fala com uma origem.
  • Em produção, direcione /api para o backend pelas configurações de rewrite ou proxy da sua hospedagem, ou sirva o frontend e a API a partir de um único servidor.

O frontend passa a chamar um caminho relativo como fetch("/api/pedidos"). Não há requisição entre origens, nenhum preflight entre origens e nenhuma dor de cabeça com cookies. Também significa que você não precisa fixar um domínio de API que muda entre a prévia e a produção.

Altere o frontend para chamar o backend com caminhos relativos /api em vez de uma URL completa, e configure um proxy de desenvolvimento para que /api seja encaminhado ao servidor da API. Depois, remova as configurações de CORS que não são mais necessárias.

O que não fazer

  • mode: "no-cors" no fetch. Não contorna nada; entrega ao seu código uma resposta vazia e ilegível.
  • Extensões do navegador que desativam o CORS. Elas mudam apenas o seu navegador. Todos os visitantes continuam vendo o erro.
  • Serviços públicos de “proxy CORS” para apps reais. Eles podem ler e alterar tudo o que passa por eles, e às vezes saem do ar.
  • Access-Control-Allow-Origin: * em uma API que usa login. Não funciona com credenciais de qualquer forma, e é o padrão errado para dados privados.
  • Refletir qualquer cabeçalho Origin de volta com credenciais permitidas. Isso permite que qualquer site faça requisições autenticadas em nome dos seus usuários. Use uma lista de permitidos.

Causas comuns em apps criados com IA

SituaçãoCorreção
O frontend chama uma API de terceiros com uma chave secretaMova a chamada para o backend
Funciona na prévia, falha no domínio publicadoAdicione as origens publicada e de domínio personalizado à lista de permitidos, ou use caminhos relativos /api
Erro apenas em POST, PUT ou DELETEPreflight não tratado; adicione o tratamento de OPTIONS e os cabeçalhos permitidos
O erro apareceu depois de adicionar loginCredenciais exigem uma origem exata e Allow-Credentials
“Erro de CORS”, mas a aba Rede mostra 500Corrija primeiro o erro do servidor
URL da API fixada em localhostUse caminhos relativos ou uma configuração por ambiente

CORS na Mythex

Quando um projeto da Mythex tem um site e um servidor de API, ambos rodam como serviços no mesmo projeto, e você pode alternar entre eles na prévia. Pedir ao agente que o frontend chame o backend por um caminho relativo /api, com proxy em desenvolvimento, evita a maioria dos problemas de CORS. Se você realmente precisar de chamadas entre origens, passe ao agente o erro exato do console e as origens envolvidas. Verifique o resultado também no app publicado, já que o endereço dele é diferente da prévia. Veja Apps com vários serviços e Backends de API na documentação, e nossos guias sobre como depurar um app criado com IA e frontend versus backend.

Checklist de CORS

  • Li o erro completo do console e o código de status da requisição que falhou
  • Descartei um 404 ou 500 escondido
  • APIs com chave secreta são chamadas pelo backend, não pelo navegador
  • O servidor envia Access-Control-Allow-Origin com as origens exatas permitidas
  • O preflight OPTIONS é respondido com os métodos e cabeçalhos permitidos, antes da autenticação
  • Os cabeçalhos de CORS também estão presentes nas respostas de erro
  • Credenciais: origem exata, Allow-Credentials: true e configurações corretas de cookie
  • Origens de prévia, publicada e de domínio personalizado cobertas, ou caminhos relativos /api usados
  • Nenhum atalho de no-cors, proxy público ou reflexão de qualquer origem

Perguntas

O que significa um erro de CORS?

Sua página, carregada de uma origem, tentou ler uma resposta de uma origem diferente, e o servidor dessa origem não incluiu cabeçalhos que permitam isso. O navegador impede que o seu código leia a resposta. A correção está no servidor, ou em como a requisição é roteada, e não no código do frontend.

Posso corrigir um erro de CORS pelo frontend?

Não de forma adequada. Configurações como mode: 'no-cors' apenas escondem a resposta do seu código. Você corrige fazendo o servidor enviar o cabeçalho Access-Control-Allow-Origin correto, ou chamando a API a partir do seu próprio backend ou de um proxy da mesma origem.

Access-Control-Allow-Origin: * é seguro?

É aceitável para dados públicos que qualquer pessoa pode ler, como uma API pública sem login. Não pode ser usado com cookies ou outras credenciais, e para APIs privadas você deve listar as origens exatas que são permitidas.

Por que minha requisição funciona no Postman ou no curl, mas não no navegador?

O CORS é aplicado apenas pelos navegadores. Ferramentas como Postman e curl não o aplicam, então uma requisição pode dar certo ali e ainda ser bloqueada quando o JavaScript da página a faz.

O que é uma requisição de preflight?

Para requisições que não são simples, como um POST com JSON ou uma com cabeçalho Authorization, o navegador primeiro envia uma requisição OPTIONS perguntando ao servidor quais métodos e cabeçalhos são permitidos. Se essa requisição OPTIONS falhar ou não tiver os cabeçalhos certos, a requisição real nunca é enviada.

Mythex · Pricing · Crie qualquer coisa com IA · Templates de sites e apps · Mythex comparado · Glossário de criação de apps com IA · Ferramentas grátis para criar apps com IA · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)