Zezwalaj na nagłówek Access-Control-Allow-Origin przy użyciu interfejsu API pobierania HTML5

87

Używam interfejsu API pobierania 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)
});

Mogę używać normalnego json, ale nie mogę pobrać danych z powyższego adresu URL interfejsu API. Wyrzuca błąd:

Fetch API nie może załadować https://davidwalsh.name/demo/arsenal.json . Żądany zasób nie zawiera nagłówka „Access-Control-Allow-Origin”. Dlatego źródło „ http: // localhost ” nie ma dostępu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na „brak elementów”, aby pobrać zasób z wyłączonym mechanizmem CORS.

iNikkz
źródło
Serwer innej firmy musi to ustawić, nic nie możesz zrobić po stronie klienta.
epascarello
@epascarello: Możemy to zrobić po stronie klienta. Za kulisami trwa żądanie XHR. Sprawdź tohttps://davidwalsh.name/fetch
iNikkz

Odpowiedzi:

81

Jak powiedział epascarello, serwer obsługujący zasób musi mieć włączony mechanizm CORS. To, co możesz zrobić po stronie klienta (i prawdopodobnie o czym myślisz), to ustawić tryb pobierania do CORS (chociaż uważam, że jest to ustawienie domyślne):

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

Jednak nadal wymaga to od serwera włączenia mechanizmu CORS i umożliwienia domenie żądania zasobu.

Zapoznaj się z dokumentacją CORS i tym niesamowitym filmem Udacity wyjaśniającym zasady tego samego pochodzenia .

Możesz także użyć trybu bez cors po stronie klienta, ale to po prostu da ci nieprzezroczystą odpowiedź (nie możesz odczytać treści, ale odpowiedź może nadal być buforowana przez Service Worker lub konsumowana przez niektóre API, na przykład <img>) :

fetch(request, {mode: 'no-cors'})
.then(function(response) {
  console.log(response); 
}).catch(function(error) {  
  console.log('Request failed', error)  
});
David Scales
źródło
2
czy możesz rozwinąć temat „Jednak nadal wymaga to od serwera włączenia mechanizmu CORS i zezwolenia Twojej domenie na żądanie zasobu”? Bezskutecznie szukałem instrukcji, jak to zrobić.
jayscript
2
@jayscript, cały proces wygląda następująco: na kliencie wykonywane jest żądanie cross-origin za pomocą javascript. W przypadku interfejsu API pobierania tryb „cors” informuje przeglądarkę, że można wysłać to żądanie. Gdybyś miał zamiast tego tryb „no-cors”, przeglądarka zatrzymałaby żądanie, ponieważ nie pochodzi ono z Twojej aplikacji. Serwer otrzyma żądanie i odpowie. W przeglądarka potwierdza, że odpowiedź ma odpowiednie nagłówki Cors, a jeśli tak, to pozwala odpowiedź do odczytu. Jeśli nie ma nagłówków, przeglądarka zgłosi błąd.
David Scales
1
@jayscript Ten artykuł w MDN zawiera szczegółowe informacje. Zasadniczo jeden serwer, którego potrzebujesz, ustaw te nagłówki: "Access-Control-Allow-Origin: foo.example ", "Access-Control-Allow-Methods: POST, GET, OPTIONS", "Access-Control-Allow-Headers: X-PINGOTHER, Content-Type ”, które włączają odpowiednio źródła, metody i nagłówki. Zwykle w nagłówku pochodzenia używa się znaku „*”. Możesz również sprawdzić ten dokument Google i powiązany plik codelab, aby dowiedzieć się więcej o interfejsie Fetch API: developers.google.com/web/ilt/pwa/working-with-the-fetch-api
David Scales
2
Dziękuję Ci! To pomaga mi zrozumieć, że niemożliwe jest pobranie danych z serwera API, który ma inne pochodzenie, gdy serwer API nie zawiera żadnych nagłówków. W konkretnym przypadku, z którym miałem do czynienia, miałem dostęp do kodu serwera API i mogłem samodzielnie dodawać nagłówki, co umożliwiało pobieranie.
jayscript
To głupie, jaki jest problem z bezpieczeństwem NO sendingplików cookie, a tym samym zezwalających na CORS?
deathangel908
14

Mój kod front-endowy działał w http: // localhost: 3000, a moje API (kod zaplecza) działało pod adresem http: // localhost: 5000

Używał interfejsu API pobierania do wywoływania interfejsu API. Początkowo wyrzucał błąd „cors”. Następnie dodałem poniższy kod w moim kodzie interfejsu API zaplecza, umożliwiając pochodzenie i nagłówek z dowolnego miejsca.

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

Jednak powinieneś ograniczyć swoje pochodzenie w przypadku innych środowisk, takich jak stage, prod.

smsivaprakaash
źródło
20
to jest okropna odpowiedź. jest to poważny problem bezpieczeństwa. jeśli to czytasz, PROSZĘ NIE ROBIĆ TEGO.
mjones.udri
1
Dotyczy to konfiguracji lokalnej. Na przykład, żeby zrobić szybkie zdjęcie. Tak, istnieje zagrożenie bezpieczeństwa, jeśli to samo dotyczy innych możliwych do wdrożenia środowisk. W przypadku miejscowych czuję, że tak nie jest. "Jednak powinieneś ograniczyć swoje pochodzenie w przypadku innych środowisk, takich jak scena, prod"
smsivaprakaash
12

To zadziałało dla mnie:

npm install -g local-cors-proxy

Punkt końcowy interfejsu API, którego chcemy zażądać i który ma problemy z CORS:

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

Uruchom serwer proxy:

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

 Proxy Active 

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

Następnie w kodzie klienta nowy punkt końcowy interfejsu API:

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

Efektem końcowym będzie żądanie do https://www.yourdomain.ie/test/list bez problemów z CORS!

VigKam
źródło
Pls upewnij się, że serwer działa równolegle. Otwórz nowe okno polecenia cmt i uruchom kod lcp --proxyUrl twojadomena.com
Govarthanan Venunathan
8

Wiem, że to starszy post, ale okazało się, że przy naprawieniu tego błędu użyłem adresu IP mojego serwera zamiast nazwy domeny w żądaniu pobierania. Na przykład:

#(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
źródło
1

Jeśli używasz nginx, spróbuj tego

#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
źródło
-3

Spójrz na https://expressjs.com/en/resources/middleware/cors.html Musisz używać cors.

Zainstalować:

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

Musisz umieścić ten kod na swoim serwerze węzłowym.

Ernersto Pastori
źródło
1
Skąd możesz wiedzieć, czy jest to serwer OP i jest napisany w NodeJs?
Marek Szkudelski
Jeśli utworzyłeś serwer węzłów (tryb programistyczny), możesz użyć tej metody, aby użyć funkcji pobierania w js.
Ernersto Pastori