Permitir cabeçalho Access-Control-Allow-Origin usando HTML5 fetch API

87

Estou usando a API de busca HTML5.

var request = new Request('https://davidwalsh.name/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});

Consigo usar o json normal, mas não consigo buscar os dados do URL da API acima. Ele gera um erro:

A API de busca não pode carregar https://davidwalsh.name/demo/arsenal.json . Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Portanto, o acesso de origem ' http: // localhost ' não é permitido. 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.

iNikkz
fonte
O servidor de terceiros precisa configurá-lo, não há nada que você possa fazer no lado do cliente.
epascarello
@epascarello: Podemos fazer no lado do cliente. Nos bastidores, a solicitação XHR está em andamento. Por favor, verifique istohttps://davidwalsh.name/fetch
iNikkz

Respostas:

81

Como disse epascarello, o servidor que hospeda o recurso precisa ter o CORS habilitado. O que você pode fazer no lado do cliente (e provavelmente no que você está pensando) é definir o modo de busca para CORS (embora esta seja a configuração padrão, eu acredito):

fetch(request, {mode: 'cors'});

No entanto, isso ainda requer que o servidor habilite o CORS também e permita que seu domínio solicite o recurso.

Confira a documentação do CORS e este incrível vídeo Udacity explicando a política da mesma origem .

Você também pode usar o modo no-cors no lado do cliente, mas isso apenas fornecerá uma resposta opaca (você não pode ler o corpo, mas a resposta ainda pode ser armazenada em cache por um service worker ou consumida por algumas APIs, como <img>) :

fetch(request, {mode: 'no-cors'})
.then(function(response) {
  console.log(response); 
}).catch(function(error) {  
  console.log('Request failed', error)  
});
David Scales
fonte
2
você pode explicar "No entanto, isso ainda requer que o servidor habilite o CORS também e permita que seu domínio solicite o recurso."? Tenho procurado sem sucesso instruções para fazer isso.
jayscript
2
@jayscript o processo geral se parece com isto: no cliente, uma solicitação de origem cruzada é feita com javascript. No caso da API de busca, o modo 'cors' informa ao navegador que está tudo bem para fazer essa solicitação. Se você tivesse o modo 'no-cors', o navegador interromperia a solicitação, porque ela não é a origem do seu aplicativo. O servidor receberá a solicitação e responderá. O navegador confirma que a resposta possui os cabeçalhos CORS apropriados e, em caso afirmativo, permite que a resposta seja lida. Se os cabeçalhos não estiverem presentes, o navegador gerará um erro.
David Scales de
1
@jayscript este artigo MDN entra em detalhes. Essencialmente, em seu servidor, você precisa definir estes cabeçalhos: "Access-Control-Allow-Origin: foo.example ", "Access-Control-Allow-Methods: POST, GET, OPTIONS", "Access-Control-Allow-Headers: X-PINGOTHER, Content-Type ", que permite origens, métodos e cabeçalhos, respectivamente. Normalmente, '*' é usado para o cabeçalho de origem. Você também pode verificar este documento do Google e codelab associado para aprender sobre a API Fetch: developers.google.com/web/ilt/pwa/working-with-the-fetch-api
David Scales
2
Obrigado! Isso me ajuda a entender que é impossível buscar dados do servidor API que tenham uma origem diferente quando o servidor API não contém nenhum cabeçalho. No caso específico que estava tratando, tive acesso ao código do servidor da API e fui capaz de adicionar cabeçalhos sozinho, o que permitiu a busca.
jayscript de
Isso é burro, qual é o problema de segurança com NO sendingcookies e, portanto, permitindo CORS?
deathangel908 de
14

Eu tinha meu código de front-end em http: // localhost: 3000 e minha API (código de back-end) em http: // localhost: 5000

Estava usando fetch API para chamar a API. Inicialmente, ele estava jogando o erro "cors". Em seguida, adicionei o código abaixo em meu código da API Backend, permitindo origem e cabeçalho de qualquer lugar.

let allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Headers', "*");
  next();
}
app.use(allowCrossDomain);

No entanto, você deve restringir suas origens no caso de outros ambientes como stage, prod.

smsivaprakaash
fonte
20
esta é uma resposta terrível. este é um grande problema de segurança. se você está lendo isso, POR FAVOR, NÃO FAÇA ISSO.
mjones.udri de
1
Isso é apenas para a configuração local. Por exemplo, para fazer um tipo de foto rápida. Sim, há um risco de segurança se o mesmo for para outros ambientes implantáveis. Para local, eu sinto que não. "No entanto, você deve restringir as origens de você no caso de outros ambientes como palco, prod"
smsivaprakaash
12

Isso funcionou para mim:

npm install -g local-cors-proxy

Endpoint de API que desejamos solicitar e que tem problemas de CORS:

https://www.yourdomain.com/test/list

Iniciar Proxy:

lcp --proxyUrl https://www.yourdomain.com

 Proxy Active 

 Proxy Url: http://www.yourdomain.com:28080
 Proxy Partial: proxy
 PORT: 8010

Em seguida, em seu código de cliente, novo endpoint de API:

http://localhost:8010/proxy/test/list

O resultado final será uma solicitação para https://www.yourdomain.ie/test/list sem os problemas do CORS!

VigKam
fonte
Por favor, certifique-se de que o servidor está executando paralelamente. Abra uma nova janela cmt-prompt e execute o código lcp --proxyUrl yourdomain.com
Govarthanan Venunathan
8

Sei que esta é uma postagem mais antiga, mas descobri que o que funcionou para corrigir esse erro foi usar o endereço IP do meu servidor em vez de usar o nome de domínio na minha solicitação de busca. Então, por exemplo:

#(original) var request = new Request('https://davidwalsh.name/demo/arsenal.json');
#use IP instead
var request = new Request('https://0.0.0.0/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});
MattG
fonte
1

Se você estiver usando o nginx, tente isso

#Control-Allow-Origin access

    # Authorization headers aren't passed in CORS preflight (OPTIONS) calls. Always return a 200 for options.
    add_header Access-Control-Allow-Credentials "true" always;
    add_header Access-Control-Allow-Origin "https://URL-WHERE-ORIGIN-FROM-HERE " always;
    add_header Access-Control-Allow-Methods "GET,OPTIONS" always;
    add_header Access-Control-Allow-Headers "x-csrf-token,authorization,content-type,accept,origin,x-requested-with,access-control-allow-origin" always;

    if ($request_method = OPTIONS ) {
        return 200;
    }

Caliari
fonte
-3

Veja https://expressjs.com/en/resources/middleware/cors.html Você tem que usar cors.

Instalar:

$ npm install cors
const cors = require('cors');
app.use(cors());

Você deve colocar este código em seu servidor de nó.

Ernersto Pastori
fonte
1
Como saber se é o servidor OP e está escrito em NodeJs?
Marek Szkudelski
Se você criou um servidor de nó (modo de desenvolvimento), pode usar esse método para usar fetch em js.
Ernersto Pastori