Na požadovanom prostriedku nie je prítomná žiadna 'Access-Control-Allow-Origin' hlavička - pri pokuse o získanie údajov z rozhrania REST API

Snažím sa získať nejaké údaje z rozhrania REST API spoločnosti HP Alm. S malým curl skriptom to funguje celkom dobre - dostanem svoje údaje.

Teraz sa zdá, že robiť to s JavaScriptom, fetch a ES6 (viac-menej) je väčší problém. Stále dostávam túto chybovú správu:

Fetch API nemôže načítať . Odpoveď na požiadavku preflight doesn't neprešla kontrolou kontroly prístupu: No 'Access-Control-Allow-Origin' header is prítomná na požadovanom zdroji. Pôvod 'http://127.0.0.1:3000' je preto nie je povolený prístup. Odpoveď mala stavový kód HTTP 501. Ak neprehľadná odpoveď slúži vašim potrebám, nastavte režim požiadavky'na 'no-cors' na získanie zdroja s vypnutým CORS.

Chápem, že je to preto, lebo sa snažím načítať tieto údaje z môjho localhostu a riešenie by malo používať CORS. Teraz som si myslel, že som to skutočne urobil, ale nejako to buď ignoruje to, čo napíšem do hlavičky, alebo je problém v niečom inom?

Je teda problém v implementácii? Robím to zle? Do logov servera sa bohužiaľ nemôžem pozrieť. Som tu naozaj trochu zaseknutý.

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Používam prehliadač Chrome. Skúšal som použiť aj ten Chrome CORS Plugin, ale potom dostávam ďalšiu chybovú správu:

Hodnota hlavičky 'Access-Control-Allow-Origin' v odpovedi

nesmie byť zástupný znak '*', keď je režim poverenia požiadavky'na 'include'. Pôvod 'http://127.0.0.1:3000' preto nie je povolený prístup. Režim poverení pri požiadavkách iniciovaných XMLHttpRequest je riadený atribútom withCredentials.

Riešenie

Táto odpoveď zahŕňa veľa tém, preto je rozdelená do troch častí:

  • Ako použiť proxy server CORS na obídenie problémov "Žiadna hlavička Access-Control-Allow-Origin "
  • Ako sa vyhnúť preflightu CORS
  • Ako vyriešiť problémy "Hlavička Access-Control-Allow-Origin nesmie byť zástupným znakom "

    Ako použiť proxy server CORS na obídenie problémov "Žiadna hlavička Access-Control-Allow-Origin " Ak nemáte kontrolu nad serverom, na ktorý váš frontendový kód JavaScriptu posiela požiadavku, a problém s odpoveďou z tohto servera spočíva len v absencii potrebnej hlavičky Access-Control-Allow-Origin, stále môžete dosiahnuť, aby všetko fungovalo - požiadavku môžete odoslať prostredníctvom proxy servera CORS. Aby sme ukázali, ako to funguje, najprv uvedieme kód, ktorý nepoužíva proxy server CORS:

const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

Dôvodom, prečo sa tam zasiahne blok catch je, že prehliadač bráni tomuto kódu v prístupe k odpovedi, ktorá sa vracia z https://example.com. A dôvodom, prečo to prehliadač robí, je, že v odpovedi chýba hlavička odpovede Access-Control-Allow-Origin. Teraz je tu presne ten istý príklad, ale len s pridaným CORS proxy:

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

Poznámka: Ak je https://cors-anywhere.herokuapp.com pri pokuse nefunkčný alebo nedostupný, potom si pozrite nižšie postup, ako nasadiť vlastný server CORS Anywhere na Heroku za 2-3 minúty. Druhý úryvok kódu uvedený vyššie môže úspešne pristupovať k odpovedi, pretože prevzatie adresy URL požiadavky a jej zmena na https://cors-anywhere.herokuapp.com/https://example.com-by len s prefixom URL proxy servera spôsobí, že požiadavka sa uskutoční prostredníctvom tohto proxy servera, ktorý potom:

  1. Presmeruje požiadavku na https://example.com.
  2. Prijíma odpoveď z adresy https://example.com.
  3. Pridá do odpovede hlavičku Access-Control-Allow-Origin.
  4. Odovzdá túto odpoveď s touto pridanou hlavičkou späť kódu frontendovej časti, ktorá o ňu požiadala. Prehliadač potom umožní frontendovému kódu prístup k odpovedi, pretože túto odpoveď s hlavičkou odpovede Access-Control-Allow-Origin prehliadač vidí. Pomocou kódu z https://github.com/Rob--W/cors-anywhere/. Funguje to celkom dobre s malým skriptom curl - dostanem svoje údaje. Ak chcete správne testovať pomocou curl, musíte emulovať požiadavku OPTIONS pred odoslaním, ktorú posiela prehliadač:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
    -H 'Access-Control-Request-Method: POST' \
    -H 'Access-Control-Request-Headers: Content-Type, Authorization' \
    "https://the.sign_in.url"

...pričom https://the.sign_in.url je nahradené akoukoľvek skutočnou adresou URL sign_in. Odpoveď, ktorú prehliadač potrebuje vidieť z tejto požiadavky OPTIONS, musí obsahovať hlavičky, ako je táto:

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

Ak odpoveď OPTIONS neobsahuje tieto hlavičky, prehliadač sa zastaví na tomto mieste a nikdy sa ani nepokúsi odoslať požiadavku POST. Takisto stavový kód HTTP pre odpoveď musí byť 2xx - typicky 200 alebo 204. Ak je to akýkoľvek iný stavový kód, prehliadač sa zastaví na tomto mieste. Server v otázke odpovedá na požiadavku OPTIONS stavovým kódom 501, čo zrejme znamená, že sa snaží naznačiť, že neimplementuje podporu pre požiadavky OPTIONS. Ostatné servery v tomto prípade zvyčajne odpovedajú stavovým kódom 405 "Metóda nie je povolená". Nikdy teda nebudete môcť z vášho frontendového kódu JavaScriptu priamo zadávať požiadavky POST na tento server, ak server na túto požiadavku OPTIONS odpovie kódom 405 alebo 501 alebo iným kódom ako 200 alebo 204, alebo ak neodpovie týmito potrebnými hlavičkami odpovede. Spôsob, ako sa vyhnúť spusteniu preflightu pre prípad uvedený v otázke, by bol nasledovný:

  • ak by server nevyžadoval hlavičku požiadavky Authorization, ale namiesto toho by sa (napríklad) spoliehal na autentifikačné údaje vložené do tela požiadavky POST alebo ako parameter dotazu
  • ak server nevyžadoval, aby telo POST obsahovalo mediálny typ Content-Type: application/json, ale namiesto toho prijal telo POST ako application/x-www-form-urlencoded s parametrom s názvom json (alebo akýmkoľvek iným), ktorého hodnotou sú údaje JSON

    Ako opraviť problémy s "Access-Control-Allow-Origin header must not be the wildcard "

    Dostávam ďalšiu chybovú správu:

    Hodnota 'Access-Control-Allow-Origin' hlavičky v odpovedi nesmie byť zástupný znak '', keď je režim poverenia požiadavky'> 'include'. Pôvod 'http://127.0.0.1:3000' preto nie je povolený prístup. Režim poverení pri požiadavkách iniciovaných XMLHttpRequest je riadený atribútom withCredentials. V prípade požiadavky, ktorá obsahuje poverenia, prehliadače nepovolia vášmu frontendovému kódu JavaScript prístup k odpovedi, ak je hodnota hlavičky odpovede Access-Control-Allow-Origin `. Namiesto toho musí hodnota v tomto prípade presne zodpovedať pôvodu vášho frontend kódu, tedahttp://127.0.0.1:3000. Pozrite si časť [*Credentialed requests and wildcards*][1] v článku MDN Kontrola prístupu HTTP (CORS). Ak ovládate server, na ktorý posielate požiadavku, potom je bežným spôsobom, ako sa s týmto prípadom vysporiadať, nakonfigurovať server tak, aby prevzal hodnotu hlavičky požiadavkyOrigina echo/odrazil ju späť do hodnoty hlavičky odpovedeAccess-Control-Allow-Origin`. Napríklad s nginx: Jazyk: lang-none -->

add_header Access-Control-Allow-Origin $http_origin

Ale to je len jeden príklad; iné (webové) serverové systémy poskytujú podobné spôsoby na echo hodnôt pôvodu.

Používam Chrome. Skúsil som použiť aj tento doplnok CORS pre Chrome Ten zásuvný modul CORS pre Chrome zrejme len prostoducho vstrekuje príkaz Access-Control-Allow-Origin: * do odpovede, ktorú prehliadač vidí. Keby bol tento zásuvný modul inteligentnejší, nastavil by hodnotu tejto falošnej hlavičky odpovede Access-Control-Allow-Origin na skutočný pôvod vášho frontendového kódu JavaScriptu, teda http://127.0.0.1:3000. Vyhnite sa preto používaniu tohto doplnku, dokonca aj na testovanie. Je to len rozptýlenie. Ak chcete otestovať, aké odpovede dostanete zo servera bez toho, aby ich prehliadač filtroval, je lepšie použiť curl -H, ako je uvedené vyššie.

Pokiaľ ide o frontendový kód JavaScript pre požiadavku fetch(...) v otázke:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Odstráňte tieto riadky. Hlavičky Access-Control-Allow-* sú hlavičky odpovede. Nikdy ich nechcete posielať v požiadavke. Jediný účinok, ktorý to bude mať, je spustenie prehliadača, aby vykonal preflight.

Komentáre (8)

Táto chyba sa vyskytne, keď sa nezhoduje adresa URL klienta a adresa URL servera vrátane čísla portu. V takom prípade je potrebné povoliť službu pre CORS, čo je zdieľanie zdrojov medzi jednotlivými pôvodcami.

Ak hostujete službu Spring REST, potom ju nájdete v príspevku na blogu CORS support in Spring Framework.

Ak hostujete službu pomocou servera Node.js, potom

  1. Zastavte server Node.js.

  2. npm install cors --save

  3. Do súboru server.js pridajte nasledujúce riadky

    var cors = require('cors')

    app.use(cors()) // Toto použite za deklaráciou premennej

Komentáre (4)

Odstráňte to:

credentials: 'include',
Komentáre (0)