Tentando usar o fetch e passar em modo: no-cors

Eu posso atingir este endpoint, http://catfacts-api.appspot.com/api/facts?number=99 via Postman e ele retorna JSON.

Além disso, estou usando o create-react-app e gostaria de evitar a configuração de qualquer configuração de servidor.

No código do meu cliente eu estou tentando usar 'fetch' para fazer a mesma coisa, mas eu recebo o erro:

Não ' Access-Control-Allow-Origin' o cabeçalho está presente no recurso. Origem 'http://localhost:3000' portanto, não é permitido acesso. Se uma resposta opaca serve as suas necessidades, defina o pedido's mode to 'nocors' para ir buscar o recurso com CORS desabilitado.

Então estou tentando passar em um objeto, para o meu Fetch que vai desabilitar CORS, assim:

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

Curiosamente, o erro que recebo é na verdade um erro de sintaxe com esta função. Não tenho certeza se o meu fetch real está quebrado, porque quando eu removo o objeto { mode: 'no-cors' }, e o forneço com um URL diferente, ele funciona muito bem.

Eu também tentei passar no objeto { mode: 'opaque'} , mas isto retorna o erro original de cima.

Acredito que tudo o que preciso de fazer é desactivar o CORS... O que estou a perder?

Adicionar mode: 'no-cors' não vai fazer as coisas funcionarem magicamente. Na verdade, isso torna as coisas piores, porque um efeito que tem é dizer aos navegadores, "Bloqueie meu código frontend JavaScript de olhar para o conteúdo do corpo de resposta e cabeçalhos em todas as circunstâncias". O que acontece com os pedidos de origem cruzada do frontend JavaScript é que os navegadores por padrão bloqueiam o código do frontend de acesso aos recursos de origem cruzada. Se um site envia Access-Control-Allow-Origin em suas respostas, então os navegadores irão relaxar esse bloqueio e permitir que seu código acesse a resposta. Mas se um site não enviar um cabeçalho "Acess-Control-Allow-Origin" em suas respostas, não há como o seu código front-end acessar diretamente as respostas desse site. Em particular, você não pode corrigir isso especificando mode: 'no-cors' (de fato isso segura* que seu código frontend não possa acessar o conteúdo da resposta). No entanto, uma coisa que virá funcionar é se você enviar seu pedido através de [um proxy CORS][1], desta forma:

var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
    targetUrl = 'http://catfacts-api.appspot.com/api/facts?number=99'
fetch(proxyUrl + targetUrl)
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    document.querySelector("pre").innerHTML = JSON.stringify(data, null, 2);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });
<pre></pre>

**Note: se quando você for tentar usar https://cors-anywhere.herokuapp.com, você descobre que está em baixo***, você também pode facilmente implantar seu próprio proxy para 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

Depois de executar esses comandos, você vai acabar com seu próprio servidor CORS Anywhere rodando em, por exemplo, https://cryptic-headland-94862.herokuapp.com/. Então, ao invés de prefixar a URL do seu pedido com `https://cors-anywhere.herokuapp.com', prefira-a com a URL da sua própria instância; por exemplo, https://cryptic-headland-94862.herokuapp.com/https://example.com.

posso chegar a este ponto final, http://catfacts-api.appspot.com/api/facts?number=99 via Carteiro https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explica porque é que, mesmo que você possa acessar a resposta com o Postman, os navegadores não permitem que você acesse a resposta com código JavaScript do frontend rodando em uma aplicação web, a menos que a resposta inclua um cabeçalho de resposta "Acess-Control-Allow-Origin". http://catfacts-api.appspot.com/api/facts?number=99 não tem um cabeçalho de resposta Access-Control-Allow-Origin', então não há como o seu código frontend acessar a resposta de origem cruzada. O seu navegador pode obter a resposta fina e você pode vê-la em Postman e até mesmo em devtools do navegador - mas isso não significa que os navegadores irão expô-la ao seu código. Eles não o farão, porque não tem um cabeçalho de resposta "Acess-Control-Allow-Origin". Então você deve, ao invés disso, usar um proxy para obtê-lo. O proxy faz o pedido àquele site, recebe a resposta, adiciona o cabeçalho de respostaAccess-Control-Allow-Origine quaisquer outros cabeçalhos CORS necessários, e depois passa isso de volta para o seu código de pedido. E essa resposta com o cabeçalhoAccess-Control-Allow-Origin' adicionado é o que o navegador vê, então o navegador permite que o seu código frontend realmente acesse a resposta.

Então estou tentando passar em um objeto, para o meu Fetch que irá desativar CORS Tu não queres fazer isso. Para ser claro, quando você diz que quer "desativar CORS", parece que na verdade você quer dizer que quer desativar a política de mesma origem. CORS é na verdade uma maneira de fazer isso - CORS é uma maneira de soltar a política de mesma origem, não uma maneira de restringi-la. Mas de qualquer forma, é verdade que você pode - apenas em seu ambiente local - fazer coisas como dar ao seu navegador bandeiras de tempo de execução para desabilitar a segurança e rodar de forma insegura, ou você pode instalar uma extensão de navegador localmente para contornar a política de mesma origem, mas tudo o que isso faz é mudar a situação apenas para você localmente. Não importa o que você mudar localmente, qualquer outra pessoa que tente usar seu aplicativo ainda vai se deparar com a política de mesma origem, e não há como você desabilitar isso para outros usuários do seu aplicativo. **Você provavelmente nunca vai querer usar mode: 'no-cors' na prática, exceto em alguns casos limitados**, e mesmo assim só se você souber exatamente o que está fazendo e quais são os efeitos. Isso porque o que a definição mode: 'no-cors' na verdade diz ao navegador é, "Bloqueie o meu código frontend JavaScript de olhar para o conteúdo do corpo de resposta e cabeçalhos em todas as circunstâncias "* Na maioria dos casos isso obviamente não é o que você quer.

Quanto aos casos em que você quereria considerar utilizar mode: 'no-cors', veja a resposta em https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 para os detalhes. A essência do problema é que os casos são:

  • No caso limitado em que você está utilizando JavaScript para fazer um recurso de outra origem o conteúdo de um <script>, ,, <amp-video>, <amp-audio>, ,, ou <iframe> elemento (que funciona porque a incorporação de recursos de origem cruzada é permitida para esses) - mas por alguma razão você não quer ou não pode fazer isso apenas por ter a marcação do documento utilize a URL do recurso como o atributo href ou src para o elemento.
  • Quando a única coisa que você quer fazer com um recurso é fazer o cache dele. Como aludido na resposta em https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790, na prática o cenário que se aplica é quando você está utilizando o Service Workers, neste caso a API que é relevante é a Cache Storage API. Mas mesmo nesses casos limitados, existem algumas gotchas importantes a serem observadas; veja a resposta em https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 para maiores detalhes.

    também tentei passar no objeto { mode: 'opaque'}`` Não hámode: 'opaque'modo pedido -opaqueé apenas uma propriedade da *resposta*, e os navegadores definem essa propriedade opaca em respostas de pedidos enviados com o modono-cors`. Mas incidentalmente a palavra opaque é um sinal bastante explícito sobre a natureza da resposta com a qual você termina: "opaco" significa que você não pode vê-la.

Comentários (5)

A solução para mim era apenas fazê-lo do lado do servidor.

Eu utilizei a biblioteca C# WebClient para obter os dados (no meu caso eram dados de imagem) e enviá-los de volta para o cliente. Lá's provavelmente algo muito similar no seu idioma escolhido do lado do servidor.

//Server side, api controller

[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
    ItemImage image = new ItemImage();

    using(WebClient client = new WebClient()){

        image.Bytes = client.DownloadData(url);

        return Ok(image);
    }
}

Pode ajustá-lo ao seu próprio caso de uso. O ponto principal é client.DownloadData() trabalhou sem nenhum erro CORS. Tipicamente os problemas CORS são apenas entre websites, por isso não há problema em fazer 'cross-site' pedidos do seu servidor.

Então a chamada para o React fetch é tão simples como:

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise)
    .then(imgResponse => {

       // Do more stuff....
    )}
Comentários (0)

Solução muito fácil (2 min para configurar) é utilizar o pacote local-ssl-proxy do npm.

O uso é muito directo:
1. instale o pacote: npm install -g local-ssl-proxy
2. Enquanto executa o seu local-server mascare-o com o local-ssl-proxy --source 9001 --target 9000

P.S: Substitua --target 9000' pelo-- "número da sua porta"e--source 9001' por --source "número da sua porta +1"

Comentários (2)