CORS: o erro que toda a gente já viu e quase ninguém explica
É provavelmente a mensagem mais copiada para o Google em toda a história do desenvolvimento web:
Access to fetch at 'https://api.exemplo.pt/dados' from origin
'https://meusite.pt' has been blocked by CORS policyE a reação mais comum é a errada: procurar como "desligar o CORS" no browser.
1. Quem bloqueia é o browser, não o servidor
A regra de origem única existe para proteger quem visita. Sem ela, um site qualquer aberto noutro separador podia fazer pedidos ao seu banco usando os cookies que já lá estão, e ler a resposta.
O CORS é a forma de um servidor dizer "com este outro sítio, pode". Repare no detalhe que muda tudo: o pedido chegou ao servidor e foi executado. O que o browser bloqueou foi o JavaScript da página ler a resposta.
2. A autorização é um cabeçalho
// No servidor
res.setHeader('Access-Control-Allow-Origin', 'https://meusite.pt');É por isso que não há nada a fazer do lado do cliente: quem tem de mudar é o servidor a que se está a pedir. Se ele não for seu, a solução é pedir a partir do seu servidor, que não tem browser nenhum a impor regras.
3. O pedido a mais: o preflight
Para pedidos que não sejam simples — um PUT, um DELETE, um cabeçalho próprio, ou Content-Type: application/json — o browser manda primeiro um OPTIONS a perguntar se pode:
OPTIONS /dados
Origin: https://meusite.pt
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type
# Resposta
Access-Control-Allow-Origin: https://meusite.pt
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: content-type
Access-Control-Max-Age: 86400O Max-Age diz ao browser quanto tempo pode guardar essa autorização. Sem ele, é um pedido a mais por cada pedido a sério.
4. A armadilha dos cookies
Para enviar cookies ou cabeçalhos de autenticação, o servidor tem de responder com Access-Control-Allow-Credentials: true — e nesse caso o asterisco deixa de ser válido. Tem de dizer a origem exata.
// Isto o browser recusa, e com razão
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: trueÉ uma proteção contra o caso em que alguém copia um "aceita tudo" de um exemplo e o põe num serviço com sessões.