Guias

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:

URLOrigem
https://minhaapp.com/dashboardhttps://minhaapp.com
https://api.minhaapp.com/usershttps://api.minhaapp.com (subdomínio diferente, por isso origem diferente)
http://localhost:5173http://localhost:5173
http://localhost:3000http://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émO que está errado
No 'Access-Control-Allow-Origin' header is presentO 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 originO servidor permite uma origem diferente da sua
Response to preflight request doesn't pass access control checkO 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 allowedO 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.com
  • Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
  • Access-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.com chama a API em https://api.minhaapp.com e recebe "Response to preflight request doesn't pass access control check". Configure o CORS na API para permitir exatamente https://minhaapp.com e 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" no fetch, ou withCredentials: true no axios.
  • O servidor envia Access-Control-Allow-Credentials: true.
  • O Access-Control-Allow-Origin do 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.proxy do Vite pode encaminhar /api para o seu backend noutra porta, para que o navegador fale sempre com uma só origem.
  • Em produção, encaminhe /api para 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" no fetch. 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 Origin com 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çãoCorreção
O frontend chama uma API de terceiros com uma chave secretaMova a chamada para o backend
Funciona na pré-visualização, falha no domínio publicadoAcrescente as origens publicada e do domínio personalizado à lista de permissões, ou use caminhos relativos /api
Erro apenas em POST, PUT ou DELETEPreflight não tratado; acrescente o tratamento de OPTIONS e os cabeçalhos permitidos
O erro apareceu depois de acrescentar o início de sessãoAs credenciais exigem uma origem exata e Allow-Credentials
"Erro de CORS", mas o separador Rede mostra 500Corrija primeiro o erro do servidor
URL da API fixo em localhostUse 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-Origin com as origens permitidas exatas
  • O preflight OPTIONS respondido 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 /api usados
  • 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.

Mythex · Pricing · Crie qualquer coisa com IA · Modelos 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 (Brasil) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)