Nincs 'Access-Control-Allow-Origin' fejléc a kért erőforráson - amikor megpróbál adatokat lekérni egy REST API-ból.

I'm megpróbálok lekérni néhány adatot a HP Alm REST API-jából. Egy kis curl szkripttel elég jól működik - megkapom az adataimat.

A JavaScript, a fetch és az ES6 (többé-kevésbé) nagyobb problémának tűnik. Folyamatosan ezt a hibaüzenetet kapom:

A Fetch API nem tudja betölteni az . A preflight-kérelemre adott válasz nem't

nem felel meg a hozzáférés-ellenőrzésnek: Nincs 'Access-Control-Allow-Origin' fejléc. nincs jelen a kért erőforráson. Origin 'http://127.0.0.1:3000' is ezért nem engedélyezett a hozzáférés. A válasz 501-es HTTP státuszkódú volt. Ha egy átláthatatlan válasz szolgálja az Ön igényeit, állítsa a kérés módját a következőre 'no-cors' az erőforrás lekérdezéséhez CORS letiltva.

Értem, hogy ez azért van, mert megpróbálom lehívni ezt az adatot a localhoston belülről, és a megoldásnak CORS-t kellene használnia. Most azt hittem, hogy ezt valóban megtettem, de valahogy vagy figyelmen kívül hagyja, amit a fejlécbe írok, vagy valami más a probléma?

Tehát valami implementációs probléma van? Rosszul csinálom? A szervernaplókat sajnos nem tudom ellenőrizni'ni. Én'tényleg egy kicsit elakadtam itt.

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

Chrome-ot használok. Próbáltam használni azt a Chrome CORS Plugint is, de akkor egy másik hibaüzenetet kapok:

A 'Access-Control-Allow-Origin' fejléc értéke a válaszban. nem lehet a vadkártya '*' ha a kérés hitelesítő módszere 'include'. A származási 'http://127.0.0.1:3000' ezért nem megengedett. hozzáférés. A hitelesítő adatok módját a kérések kezdeményezett a XMLHttpRequest által kezdeményezett kéréseket a withCredentials attribútum vezérli.

Megoldás

Ez a válasz sok mindent felölel, ezért három részre oszlik:

  • Hogyan használjunk CORS-proxyt a "No Access-Control-Allow-Origin header " problémák megkerülésére?
  • Hogyan kerüljük el a CORS preflight-ot?
  • Hogyan lehet megoldani az "Access-Control-Allow-Origin fejléc nem lehet joker" problémákat?

    Hogyan használjunk CORS proxy-t a "Nincs Access-Control-Allow-Origin fejléc " problémák megkerülésére Ha nem Ön irányítja a szervert, amelyre a frontend JavaScript kódja kérést küld, és a szerver válaszával kapcsolatos probléma csupán a szükséges "Access-Control-Allow-Origin" fejléc hiánya, akkor is megoldható a dolog - a kérés CORS proxy-n keresztül történő végrehajtásával. Hogy megmutassuk, hogyan működik ez, először is itt van néhány olyan kód, amely nem használ CORS proxyt:

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?"))

A catch blokk azért kerül oda, mert a böngésző megakadályozza, hogy ez a kód hozzáférjen a válaszhoz, ami a https://example.com-ról jön vissza. A böngésző ezt azért teszi, mert a válaszból hiányzik az Access-Control-Allow-Origin válaszfejléc. Most pedig itt van pontosan ugyanaz a példa, csak egy CORS proxyval kiegészítve:

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?"))

Figyelem: Ha a https://cors-anywhere.herokuapp.com nem elérhető vagy nem elérhető, amikor megpróbálod, akkor lásd alább, hogyan telepítheted a saját CORS Anywhere szerveredet a Herokunál mindössze 2-3 perc alatt. A fenti második kódrészlet sikeresen elérheti a választ, mert a kérési URL-t a https://cors-anywhere.herokuapp.com/https://example.com-by címre változtatva, csak a proxy URL előtagját kell előtte megadni - a kérés a proxy-n keresztül történik, ami aztán:

  1. Továbbítja a kérést a "https://example.com" címre.
  2. A választ a "https://example.com"-tól kapja.
  3. Hozzáadja a válaszhoz az Access-Control-Allow-Origin fejlécet.
  4. Átadja a választ a hozzáadott fejléccel együtt a kérő frontend kódnak. A böngésző ezután engedélyezi a frontend kód számára a válasz elérését, mivel a böngésző ezt a választ látja az Access-Control-Allow-Origin válaszfejléccel. A https://github.com/Rob--W/cors-anywhere/. Ez elég jól működik egy kis curl szkript - megkapom az adataimat. A curl megfelelő teszteléséhez emulálnia kell a böngésző által küldött, az OPTIONS előtti kérést:
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"

...a https://the.sign_in.url helyett a tényleges sign_in URL-t. A böngésző által az OPTIONS kérésre kapott válasznak ilyen fejléceket kell tartalmaznia:

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

Ha az OPTIONS válasz nem tartalmazza ezeket a fejléceket, akkor a böngésző itt megáll, és meg sem próbálja elküldeni a POST kérést. A válasz HTTP státuszkódjának is 2xx-nek kell lennie - tipikusan 200 vagy 204. Ha ez bármilyen más státuszkód, akkor a böngésző azonnal leáll. A kérdéses szerver 501-es státuszkóddal válaszol az "OPTIONS" kérésre, ami nyilvánvalóan azt jelenti, hogy nem támogatja az "OPTIONS" kéréseket. Más szerverek ebben az esetben általában 405 "Method not allowed" státuszkóddal válaszolnak. Tehát soha nem fogsz tudni POST kéréseket intézni közvetlenül a szerverhez a frontend JavaScript kódodból, ha a szerver 405 vagy 501 vagy bármi mással válaszol az OPTIONS kérésre, mint 200 vagy 204, vagy ha nem válaszol a szükséges válaszfejlécekkel. A kérdésben szereplő esetben a következőképpen kerülhetjük el a preflight kiváltását:

  • ha a kiszolgáló nem követeli meg az Authorization kérésfejlécet, hanem (például) a POST kérés testébe vagy lekérdezési paraméterként beágyazott hitelesítési adatokra támaszkodik.
  • ha a kiszolgáló nem követeli meg, hogy a POST testnek Content-Type: application/json médiatípust kelljen tartalmaznia, hanem a POST testet application/x-www-form-urlencoded formátumban fogadja el egy json (vagy bármi más) nevű paraméterrel, amelynek értéke a JSON adat

    Hogyan lehet megoldani az "Access-Control-Allow-Origin fejléc nem lehet a vadkártya " problémákat

    Egy másik hibaüzenetet kapok:

    A válaszban szereplő 'Access-Control-Allow-Origin' fejléc értéke nem lehet a joker '', ha a kérés hitelesítő módszere 's 'include'. A származási 'http://127.0.0.1:3000' ezért nem megengedett. hozzáférés. A hitelesítő adatok módját a kérések által kezdeményezett XMLHttpRequest által kezdeményezett kérelmeket a withCredentials attribútum vezérli. A hitelesítő adatokat tartalmazó kérések esetében a böngészők nem engedik, hogy a frontend JavaScript kódja hozzáférjen a válaszhoz, ha az Access-Control-Allow-Origin válaszfejléc értéke `. Ehelyett az értéknek ebben az esetben pontosan meg kell egyeznie a frontend kódjának eredetével, ahttp://127.0.0.1:3000értékkel. Lásd [*Credentialed requests and wildcards*][1] az MDN HTTP hozzáférés-szabályozás (CORS) című cikkében. Ha Ön irányítja a kiszolgálót, ahová a kérést küldi, akkor az ilyen eset kezelésének gyakori módja, hogy a kiszolgálót úgy konfigurálja, hogy vegye át aOriginkérési fejléc értékét, és azt visszhangozza/tükrözze vissza aAccess-Control-Allow-Origin` válaszfejléc értékébe. Például az nginx-szel:

add_header Access-Control-Allow-Origin $http_origin

De ez csak egy példa; más (web)szerverrendszerek is hasonló módon biztosítják az eredetértékek visszhangozását.

Én a Chrome-ot használom. Megpróbáltam a Chrome CORS Plugin használatát is. Az a Chrome CORS plugin nyilvánvalóan csak egyszerűen befecskendez egy Access-Control-Allow-Origin: * fejlécet a válaszba, amit a böngésző lát. Ha a plugin okosabb lenne, akkor a hamis Access-Control-Allow-Origin válaszfejléc értékét az Ön frontend JavaScript kódjának tényleges eredetére, a http://127.0.0.1:3000 értékére állítaná. Kerülje tehát a plugin használatát, még tesztelés céljából is. Csak eltereli a figyelmet. Ha azt akarod tesztelni, hogy milyen válaszokat kapsz a szervertől anélkül, hogy a böngésző szűrné azokat, akkor jobb, ha a curl -H-t használod, mint fentebb.

Ami a kérdésben szereplő fetch(...) kérés frontend JavaScript kódját illeti:

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

Távolítsa el ezeket a sorokat. Az Access-Control-Allow-* fejlécek válasz fejlécek. Soha nem akarod őket kérésben elküldeni. Az egyetlen hatása az, hogy a böngészőt előflightolásra készteti.

Kommentárok (8)

Ez a hiba akkor jelentkezik, ha az ügyfél URL és a kiszolgáló URL címe nem egyezik, beleértve a portszámot is. Ebben az esetben engedélyeznie kell a szolgáltatását a CORS, azaz a cross origin resource sharing (kereszt eredetű erőforrás-megosztás) számára.

Ha Spring REST szolgáltatást üzemeltet, akkor ezt a CORS támogatás a Spring Frameworkben blogbejegyzésben találja.

Ha egy Node.js szerverrel rendelkező szolgáltatást hosztolsz, akkor

  1. Állítsa le a Node.js kiszolgálót.

  2. npm install cors --save.

  3. Adjuk hozzá a következő sorokat a server.js fájlhoz

    var cors = require('cors')

    app.use(cors()) // Használja ezt a változó deklarációja után

Kommentárok (4)

Távolítsa el ezt:

credentials: 'include',
Kommentárok (0)