Esta resposta cobre muito terreno, por isso é dividida em três partes:
- Como usar um proxy CORS dar a volta “No Access-Control-Allow-Origin cabeçalho” problemas
- Como evitar o preflight do CORS
- Como corrigir os problemas do cabeçalho "Acesso-controle-permissão-origem" não deve ser o curinga
Como usar um proxy CORS dar a volta “No Access-Control-Allow-Origin cabeçalho” problemas
Se você não controlar o servidor, seu código JavaScript de front-end está enviando uma solicitação e o problema com a resposta desse servidor é apenas a falta do Access-Control-Allow-Origin
cabeçalho necessário , você ainda poderá fazer as coisas funcionarem - fazendo a solicitação por meio de um Proxy CORS. Para mostrar como isso funciona, primeiro, aqui está um código que não usa um proxy CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
O motivo pelo qual o catch
bloco é atingido é que o navegador impede que esse código acesse a resposta da qual ele volta https://example.com
. E a razão pela qual o navegador faz isso é que a resposta não possui o Access-Control-Allow-Origin
cabeçalho de resposta.
Agora, aqui está exatamente o mesmo exemplo, mas apenas com um proxy CORS adicionado em:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Nota: Se https://cors-anywhere.herokuapp.com estiver inativo ou indisponível quando você o experimentar, veja abaixo como implantar seu próprio servidor CORS Anywhere no Heroku em apenas 2-3 minutos.
O segundo trecho de código acima pode acessar a resposta com êxito, porque pegar o URL da solicitação e alterá-lo para https://cors-anywhere.herokuapp.com/https://example.com - apenas prefixando-o com o URL do proxy - causa o solicitação a ser feita através desse proxy, que então:
- Encaminha a solicitação para
https://example.com
.
- Recebe a resposta de
https://example.com
.
- Adiciona o
Access-Control-Allow-Origin
cabeçalho à resposta.
- Passa essa resposta, com esse cabeçalho adicionado, de volta ao código de front-end solicitante.
O navegador então permite que o código de front-end acesse a resposta, porque essa resposta com o Access-Control-Allow-Origin
cabeçalho da resposta é o que o navegador vê.
Você pode executar facilmente seu próprio proxy usando o código de https://github.com/Rob--W/cors-anywhere/ .
Você também pode implantar facilmente seu próprio proxy no Heroku em literalmente apenas 2-3 minutos, com 5 comandos:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Após a execução desses comandos, você terminará com seu próprio servidor CORS Anywhere em execução, por exemplo, em https://cryptic-headland-94862.herokuapp.com/ . Portanto, em vez de prefixar seu URL de solicitação https://cors-anywhere.herokuapp.com
, prefixe-o com o URL da sua própria instância; por exemplo, https://cryptic-headland-94862.herokuapp.com/https://example.com .
Portanto, se você tentar usar https://cors-anywhere.herokuapp.com, descobrir que está em baixo (o que às vezes acontece), considere obter uma conta Heroku (se ainda não o fez) e faça 2 ou 3 minutos para executar as etapas acima para implantar seu próprio servidor CORS Anywhere no Heroku.
Independentemente de você executar ou usar https://cors-anywhere.herokuapp.com ou outro proxy aberto, esta solução funcionará mesmo se a solicitação for aquela que aciona os navegadores para fazer uma OPTIONS
solicitação de comprovação CORS - porque, nesse caso, o O proxy também envia de volta os cabeçalhos Access-Control-Allow-Headers
e Access-Control-Allow-Methods
necessários para tornar o preflight bem-sucedido.
Como evitar o preflight do CORS
O código na pergunta aciona um preflight do CORS, pois envia um Authorization
cabeçalho.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Mesmo sem isso, o Content-Type: application/json
cabeçalho também acionaria o preflight.
O que “comprovar” significa: antes que o navegador tente digitar o POST
código da pergunta, ele primeiro envia uma OPTIONS
solicitação ao servidor - para determinar se o servidor está optando por receber uma origem cruzada POST
que inclua os cabeçalhos Authorization
e Content-Type: application/json
.
Funciona muito bem com um pequeno script curl - eu recebo meus dados.
Para testar corretamente curl
, você deve emular a OPTIONS
solicitação de comprovação que o navegador envia:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
... https://the.sign_in.url
substituído por qualquer que seja o seu sign_in
URL real .
A resposta que o navegador precisa receber dessa OPTIONS
solicitação deve incluir cabeçalhos como este:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Se a OPTIONS
resposta não incluir esses cabeçalhos, o navegador será interrompido e nunca tentará enviar a POST
solicitação. Além disso, o código de status HTTP para a resposta deve ser 2xx - normalmente 200 ou 204. Se houver outro código de status, o navegador irá parar ali.
O servidor na pergunta está respondendo à OPTIONS
solicitação com um código de status 501, o que aparentemente significa que está tentando indicar que não implementa suporte para OPTIONS
solicitações. Outros servidores normalmente respondem com um código de status 405 "Método não permitido" neste caso.
Portanto, você nunca poderá fazer POST
solicitações diretamente a esse servidor a partir do seu código JavaScript de front-end se o servidor responder a essa OPTIONS
solicitação com um 405 ou 501 ou qualquer coisa que não seja um 200 ou 204 ou se não responder com os necessários cabeçalhos de resposta.
A maneira de evitar o desencadeamento de um preflight para o caso na pergunta seria:
- se o servidor não exigir um
Authorization
cabeçalho de solicitação, mas (por exemplo) se basear nos dados de autenticação incorporados no corpo da POST
solicitação ou como um parâmetro de consulta
- se o servidor não exigiu que o
POST
corpo tivesse um Content-Type: application/json
tipo de mídia, mas o aceitou POST
como application/x-www-form-urlencoded
com um parâmetro chamado json
(ou qualquer outro) cujo valor são os dados JSON
Como corrigir os problemas do cabeçalho "Acesso-controle-permissão-origem" não deve ser o curinga
Estou recebendo outra mensagem de erro:
O valor do cabeçalho 'Access-Control-Allow-Origin' na resposta não deve ser o curinga '*' quando o modo de credenciais da solicitação for 'include'. Portanto, a origem ' http://127.0.0.1:3000 ' não é permitida. O modo de credenciais de solicitações iniciadas pelo XMLHttpRequest é controlado pelo atributo withCredentials.
Para uma solicitação que inclui credenciais, os navegadores não permitirão que o código JavaScript do front-end acesse a resposta se o valor do Access-Control-Allow-Origin
cabeçalho da resposta for *
. Em vez disso, o valor nesse caso deve corresponder exatamente à origem do seu código de front-end http://127.0.0.1:3000
,.
Consulte Solicitações credenciadas e curingas no artigo MDN HTTP access control (CORS).
Se você controla o servidor para o qual está enviando a solicitação, uma maneira comum de lidar com esse caso é configurar o servidor para pegar o valor do Origin
cabeçalho da solicitação e repetir / refletir isso no valor do Access-Control-Allow-Origin
cabeçalho da resposta. Por exemplo, com nginx:
add_header Access-Control-Allow-Origin $http_origin
Mas esse é apenas um exemplo; outros sistemas de servidor (web) fornecem maneiras semelhantes de ecoar valores de origem.
Estou usando o Chrome. Eu também tentei usar o Chrome CORS Plugin
Esse plug-in do Chrome CORS aparentemente injeta simplesmente um Access-Control-Allow-Origin: *
cabeçalho na resposta que o navegador vê. Se o plug-in fosse mais inteligente, o que estaria fazendo seria definir o valor desse Access-Control-Allow-Origin
cabeçalho de resposta falsa para a origem real do seu código JavaScript de front-end http://127.0.0.1:3000
,.
Portanto, evite usar esse plug-in, mesmo para testes. É apenas uma distração. Se você deseja testar quais respostas você obtém do servidor sem que o navegador as filtre, é melhor usá-lo curl -H
como acima.
Quanto ao código JavaScript de front-end para a fetch(…)
solicitação na pergunta:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Remova essas linhas. Os Access-Control-Allow-*
cabeçalhos são cabeçalhos de resposta . Você nunca deseja enviá-los em uma solicitação. O único efeito que isso terá é acionar um navegador para realizar um preflight.