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?

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.


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 .


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: *");


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....
    )}

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"


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.