Tentando usar o modo de busca e passagem: no-cors

166

Eu posso atingir esse endpoint http://catfacts-api.appspot.com/api/facts?number=99via Postman e ele retornaJSON

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

No código do meu cliente, estou tentando usar fetcha mesma coisa, mas recebo o erro:

Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. A origem ' http: // localhost: 3000 ' não é, portanto, permitido o acesso. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desativado.

Então, eu estou tentando passar um objeto, para o meu Fetch que irá desativar o 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 é realmente um erro de sintaxe com esta função. Não tenho certeza se meu valor fetchestá quebrado, porque quando removo o objeto {mode: 'no-cors'} e o forneço uma URL diferente, ele funciona perfeitamente.

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

Acredito que tudo o que preciso fazer é desativar o CORS. O que estou perdendo?

dwww
fonte

Respostas:

290

mode: 'no-cors'magicamente não fará as coisas funcionarem. Na verdade, isso piora as coisas, porque um efeito que ele tem é dizer aos navegadores: "Bloqueie meu código JavaScript de front-end de examinar o conteúdo do corpo da resposta e dos cabeçalhos em todas as circunstâncias". Claro que você quase nunca quer isso.

O que acontece com solicitações de origem cruzada do JavaScript de front-end é que os navegadores, por padrão, bloqueiam o código de front-end de acessar recursos de origem cruzada. Se Access-Control-Allow-Originhouver uma resposta, os navegadores relaxarão esse bloqueio e permitirão que seu código acesse a resposta.

Mas se um site não envia Access-Control-Allow-Originrespostas, o código do front-end não pode acessar diretamente as respostas desse site. Em particular, você não pode corrigi-lo especificando mode: 'no-cors'(de fato, isso garantirá que seu código de front-end não possa acessar o conteúdo da resposta).

No entanto, uma coisa que vai funcionar: se você enviar o seu pedido através de um proxy CORS , como este:

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>

Nota: se você tentar usar https://cors-anywhere.herokuapp.com, descobrir que está desativado , também poderá 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 executar esses 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 .


Eu posso atingir esse endpoint, http://catfacts-api.appspot.com/api/facts?number=99via Postman

https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Access_control_CORS explica por que, mesmo que você possa acessar a resposta com o Postman, os navegadores não permitem acessar a resposta entre origens da interface Código JavaScript em execução em um aplicativo Web, a menos que a resposta inclua um Access-Control-Allow-Origincabeçalho de resposta.

http://catfacts-api.appspot.com/api/facts?number=99 não tem Access-Control-Allow-Origincabeçalho de resposta, portanto, não há como seu código de front-end acessar a origem de resposta.

Seu navegador pode obter a resposta perfeita e você pode vê-la no Postman e até nas ferramentas do navegador - mas isso não significa que os navegadores a exponham ao seu código. Eles não vão, porque não tem Access-Control-Allow-Origincabeçalho de resposta. Portanto, você deve usar um proxy para obtê-lo.

O proxy faz a solicitação para esse site, obtém a resposta, adiciona o Access-Control-Allow-Origincabeçalho de resposta e quaisquer outros cabeçalhos CORS necessários e depois o transmite de volta ao seu código solicitante. E essa resposta com o Access-Control-Allow-Origincabeçalho adicionado é o que o navegador vê; portanto, o navegador permite que seu código de front-end realmente acesse a resposta.


Então, eu estou tentando passar um objeto, para o meu Fetch, que irá desativar o CORS

Você não quer fazer isso. Para ser claro, quando você diz que deseja "desativar o CORS", parece que realmente quer dizer que deseja desativar a política de mesma origem . O próprio CORS é realmente uma maneira de fazer isso - o CORS é uma maneira de afrouxar a política de mesma origem, não uma maneira de restringi-la.

De qualquer forma, é verdade que você pode - apenas no seu ambiente local - executar ações como dar sinalizadores de tempo de execução ao navegador para desativar a segurança e executar de forma insegura, ou instalar uma extensão do navegador localmente para contornar a política de mesma origem, mas tudo o que faz é mudar a situação apenas para você localmente.

Não importa o que você altere localmente, qualquer outra pessoa que tentar usar seu aplicativo ainda terá a mesma política de origem e não há como desabilitar isso para outros usuários do seu aplicativo.

É provável que você nunca queira usar mode: 'no-cors'na prática, exceto em alguns casos limitados , e mesmo assim apenas se souber exatamente o que está fazendo e quais são os efeitos. Isso mode: 'no-cors'ocorre porque a configuração realmente diz ao navegador: "Bloqueie meu código JavaScript de front-end de examinar o conteúdo do corpo da resposta e dos cabeçalhos em todas as circunstâncias". Na maioria dos casos, isso obviamente não é exatamente o que você deseja.


Quanto aos casos em que você gostaria de considerar o uso mode: 'no-cors', consulte a resposta em Quais limitações se aplicam a respostas opacas? para os detalhes. A essência disso é que os casos são:

  • No caso limitada quando você está usando JavaScript para fazer um recurso de outra origem o conteúdo de um <script>, <link rel=stylesheet>, <img>, <video>, <audio>, <object>, <embed>, ou <iframe>elemento (que funciona porque a incorporação de recursos de origem cruzada é permitido para aqueles) - mas por alguma razão você não deseja ou não pode fazer isso apenas fazendo com que a marcação do documento use a URL do recurso como o atributo hrefou srcdo elemento.

  • Quando a única coisa que você deseja fazer com um recurso é armazená-lo em cache. Como mencionado na resposta em Quais limitações se aplicam a respostas opacas? , na prática, o cenário a que se aplica é quando você está usando Service Workers. Nesse caso, a API relevante é a API de armazenamento em cache .

Mas mesmo nesses casos limitados, há algumas dicas importantes a serem observadas; veja a resposta em Quais limitações se aplicam a respostas opacas? para os detalhes.


Eu também tentei passar o objeto { mode: 'opaque'}

Não há mode: 'opaque'modo de solicitação - opaqueé apenas uma propriedade da resposta e os navegadores definem essa propriedade opaca nas respostas de solicitações enviadas com o no-corsmodo.

Mas, aliás, a palavra opaco é um sinal bastante explícito sobre a natureza da resposta com a qual você termina: "opaco" significa que você não pode vê-lo.

sideshowbarker
fonte
4
Adore a cors-anywheresolução alternativa para casos de uso simples que não sejam de prod (como buscar alguns dados publicamente disponíveis). Essa resposta confirma minha suspeita de que isso no-corsnão é comum porque o seu OpaqueResponse não é muito útil; ie "casos muito limitados"; alguém pode me explicar exemplos onde no-corsé útil?
The Red Pea
1
@TheRedPea Veja a atualização que eu fiz para a resposta aqui (e que eu também adicionei como comentários para sua pergunta em stackoverflow.com/questions/52569895/… )
sideshowbarker
Eu precisava para configurar meu servidor Express com o pacote CORS.js - github.com/expressjs/cors - e então eu precisava para remover mode: 'no-cors'a partir da solicitação de busca (caso contrário, a resposta seria vazia)
James L.
o proxy CORS é ótimo. Surpreende-me que seja considerada uma medida de "segurança" para bloquear o acesso a arquivos públicos. É tão, tão fácil de se locomover da perspectiva de um hacker, e é exatamente isso que isso faz. É realmente apenas um aborrecimento para bons atores.
Seph Reed
Eu gero o código de diferentes clientes consumindo a mesma API. Eu uso isso para treinamentos. Quero manter o código simples e deixar os usuários jogarem com ele. Eu preciso usar no-cros.
profimedica 01/12/19
6

Portanto, se você é como eu e está desenvolvendo um site no host local onde está tentando buscar dados da API do Laravel e usá-los no front-end do Vue, e vê esse problema, aqui está como eu o resolvi:

  1. Em seu projeto Laravel, comando executar php artisan make:middleware Cors. Isso criará app/Http/Middleware/Cors.phppara você.
  2. Adicione o seguinte código dentro da handlesfunção em Cors.php:

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  3. Em app/Http/kernel.php, adicione a seguinte entrada na $routeMiddlewarematriz:

    cors => \App\Http\Middleware\Cors::class

    (Existem outras entradas na matriz como auth, guestetc. Também verifique se você está fazendo isso app/Http/kernel.phpporque há outra kernel.phptambém no Laravel)

  4. Adicione este middleware no registro de rotas para todas as rotas às quais você deseja permitir acesso, como este:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
  5. No front-end do Vue, chame essa API em mounted()função e não em data(). Verifique também se você usa http://ou https://com o URL em sua fetch()chamada.

Créditos completos para o artigo de blog de Pete Houston .

ponto Net
fonte
3

A solução simples: adicione o seguinte ao topo do arquivo php do qual você está solicitando os dados.

header("Access-Control-Allow-Origin: *");

Really Nice Code
fonte
7
Essa é uma ideia muito boa, se você quiser o mínimo de segurança possível :).
Heretic Monkey
what about image hotlink
user889030 em
1

A solução para mim foi apenas fazê-lo no lado do servidor

Usei a WebClientbiblioteca C # para obter os dados (no meu caso, eram dados de imagem) e enviá-los de volta ao cliente. Provavelmente há algo muito semelhante no 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);
    }
}

Você pode ajustá-lo para qualquer que seja seu caso de uso. O ponto principal é client.DownloadData()trabalhado sem erros do CORS. Normalmente, os problemas do CORS são apenas entre sites, portanto, não há problema em fazer solicitações "entre sites" do seu servidor.

Em seguida, a chamada de busca de reação é tão simples quanto:

//React component

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

       // Do more stuff....
    )}
Stuart Aitken
fonte
1

A solução muito fácil (2 minutos para a configuração) é usar o pacote local-ssl-proxy denpm

O uso é direto:
1. Instale o pacote: npm install -g local-ssl-proxy
2. Enquanto estiver executando sua local-servermáscara, com olocal-ssl-proxy --source 9001 --target 9000

PS: Substitua --target 9000por -- "number of your port"e --source 9001com--source "number of your port +1"

volna
fonte
1
Estou com problemas ao usar meu aplicativo no dispositivo de telefone real. Sua solução é útil para este caso?
Hamid Araghi 18/07/19
@HamidAraghi I am suporia que agora, uma vez que para fins de desenvolvimento do servidor proxy deve em execução no dispositivo que está realmente afetados pelo erro
volna