Na zahtevanem viru ni glave 'Access-Control-Allow-Origin' - ko poskušate pridobiti podatke iz vmesnika API REST

Poskušam pridobiti nekaj podatkov iz API REST podjetja HP Alm. Z majhno skripto curl deluje dokaj dobro - dobim svoje podatke.

Zdaj pa se zdi, da je to z JavaScript, fetch in ES6 (bolj ali manj) večja težava. Vedno znova dobim to sporočilo o napaki:

Fetch API ne more naložiti . Odziv na zahtevo za predizpolnitev ni

ne prestane preverjanja kontrole dostopa: Ni 'Access-Control-Allow-Origin' glave prisotna na zahtevanem viru. Izvor 'http://127.0.0.1:3000' je zato dostop ni dovoljen. Odgovor je imel kodo stanja HTTP 501. Če nepregleden odgovor ustreza vašim potrebam, nastavite način zahteve na 'no-cors' za pridobitev vira z onemogočenim CORS.

Razumem, da je to zato, ker poskušam te podatke pridobiti iz svojega lokalnega gostitelja in bi morala biti rešitev uporaba CORS. Zdaj sem mislil, da sem to dejansko storil, vendar nekako ne upošteva tega, kar sem napisal v glavi, ali pa je težava v čem drugem?

Torej, ali gre za težavo pri izvajanju? Ali to počnem narobe? Na žalost ne morem preveriti dnevnikov strežnika. Tu sem se res malo zataknil.

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

Uporabljam Chrome. Poskušal sem uporabiti tudi vtičnik CORS za Chrome, vendar sem dobil drugo sporočilo o napaki:

Vrednost glave 'Access-Control-Allow-Origin' v odgovoru

ne sme biti nadomestni znak '*', kadar je način poverilnic zahteve 'include'. Izvor 'http://127.0.0.1:3000' torej ni dovoljen. dostop. Način poverilnic pri zahtevah, ki jih sproži XMLHttpRequest, nadzoruje atribut withCredentials.

Rešitev

Ta odgovor zajema veliko področij, zato je razdeljen na tri dele:

  • Kako uporabiti posrednika CORS, da obidete težave "Ni glave Access-Control-Allow-Origin ".
  • Kako se izogniti predhodnemu pregledu CORS
  • Kako odpraviti težave "Glavička Access-Control-Allow-Origin ne sme biti nadomestni znak "

    Kako uporabiti posrednika CORS za izogibanje težavam "Ni glave Access-Control-Allow-Origin " Če nimate nadzora nad strežnikom, ki mu vaša koda JavaScript pošilja zahtevo, in je težava z odgovorom tega strežnika le pomanjkanje potrebne glave Access-Control-Allow-Origin, lahko še vedno poskrbite za delovanje tako, da zahtevo pošljete prek posrednika CORS. Da bi pokazali, kako to deluje, najprej predstavljamo nekaj kode, ki ne uporablja posredniškega strežnika 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?"))

Blok catch je tam zadet zato, ker brskalnik preprečuje tej kodi dostop do odgovora, ki se vrne s strani https://example.com. Razlog za to je, da v odgovoru ni glave odgovora Access-Control-Allow-Origin. Tukaj je popolnoma enak primer, vendar z dodanim posrednikom CORS:

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

Pomnilo: Če je https://cors-anywhere.herokuapp.com ob poskusu nedelujoč ali nedostopen, glejte spodaj, kako v samo 2-3 minutah namestite svoj strežnik CORS Anywhere na Heroku. Drugi zgornji del kode lahko uspešno dostopa do odgovora, ker se ob prevzemu URL-ja zahteve in njegovi spremembi v https://cors-anywhere.herokuapp.com/https://example.com-by samo s predpono URL-ja posrednika povzroči, da se zahteva izvede prek tega posrednika, ki nato:

  1. posreduje zahtevo na naslov https://example.com.
  2. prejme odgovor od https://example.com.
  3. V odgovor doda glavo Access-Control-Allow-Origin.
  4. Ta odgovor z dodano glavo posreduje nazaj kodi sprednjega dela, ki je zahtevala odgovor. Brskalnik nato omogoči dostop do odgovora prednji kodi, saj je ta odgovor z glavo Access-Control-Allow-Origin tisto, kar vidi brskalnik. Z uporabo kode iz https://github.com/Rob--W/cors-anywhere/. Deluje precej dobro z majhno skripto curl - dobim svoje podatke. Za pravilno testiranje z curl morate posnemati zahtevo OPTIONS, ki jo pošlje brskalnik:
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"

...z https://the.sign_in.url, ki ga zamenja dejanski naslov URL vašega prijave_in. Odgovor, ki ga mora brskalnik videti na podlagi te zahteve OPTIONS, mora vsebovati glave, kot je ta:

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

Če odgovor OPTIONS ne vsebuje teh glave, se brskalnik ustavi na tej točki in nikoli ne poskuša poslati zahteve POST. Poleg tega mora biti koda stanja HTTP za odgovor 2xx - običajno 200 ali 204. Če je to katera koli druga koda stanja, se brskalnik takoj ustavi. Strežnik v vprašanju se na zahtevo OPTIONS odzove s kodo stanja 501, kar očitno pomeni, da poskuša sporočiti, da ne izvaja podpore za zahteve OPTIONS. Drugi strežniki se v tem primeru običajno odzovejo s statusno kodo 405 "Metoda ni dovoljena". Zato nikoli ne boste mogli izvajati zahtevkov POST neposredno v ta strežnik iz svoje kode JavaScript v sprednjem delu, če se strežnik na zahtevo OPTIONS odzove s kodo 405 ali 501 ali kar koli drugega kot 200 ali 204 ali če se ne odzove s temi potrebnimi glavami odgovora. V primeru iz vprašanja bi se izognili sprožitvi predizbrisa na naslednji način:

  • če strežnik ne bi zahteval glave zahteve Authorization, temveč bi se (na primer) zanašal na podatke o avtentikaciji, vgrajene v telo zahteve POST ali kot parameter poizvedbe
  • če strežnik ni zahteval, da ima telo POST medijsko vrsto Content-Type: application/json, ampak je namesto tega sprejel telo POST kot application/x-www-form-urlencoded s parametrom json (ali kako drugače), katerega vrednost so podatki JSON

    Kako odpraviti težave "Naslovnica Access-Control-Allow-Origin ne sme biti nadomestni znak "

    dobim še eno sporočilo o napaki:

    Vrednost glave 'Access-Control-Allow-Origin' v odgovoru ne sme biti nadomestni znak '', če je način poverilnic zahteve 'include'. Izvor 'http://127.0.0.1:3000' torej ni dovoljen. dostop. Način poverilnic pri zahtevah, ki jih sproži XMLHttpRequest, nadzoruje atribut withCredentials. Za zahtevo, ki vključuje poverilnice, brskalniki ne bodo dovolili vaši sprednji kodi JavaScript dostopa do odgovora, če je vrednost glave odgovora Access-Control-Allow-Origin `. Namesto tega se mora vrednost v tem primeru natančno ujemati z izvorom vaše kode sprednjega dela, torejhttp://127.0.0.1:3000. Oglejte si [*Credentialed requests and wildcards*][1] v članku MDN Nadzor dostopa HTTP (CORS). Če nadzorujete strežnik, ki mu pošiljate zahtevo, je običajen način reševanja tega primera konfiguracija strežnika, da vzame vrednost glave zahteveOriginin jo ponovi/odrazi nazaj v vrednost glave odgovoraAccess-Control-Allow-Origin`. Na primer z nginxom: jezik: lang-none -->

add_header Access-Control-Allow-Origin $http_origin

Vendar je to le en primer; drugi sistemi (spletnih) strežnikov zagotavljajo podobne načine za odmev vrednosti izvora.

Uporabljam Chrome. Poskusil sem uporabiti tudi vtičnik CORS za Chrome Ta vtičnik CORS za Chrome očitno preprosto vnese Access-Control-Allow-Origin: *v odgovor, ki ga vidi brskalnik. Če bi bil vtičnik pametnejši, bi nastavil vrednost lažne glaveAccess-Control-Allow-Originodgovora na dejanski izvor vaše kode JavaScript v sprednjem delu, torej nahttp://127.0.0.1:3000. Zato se izogibajte uporabi tega vtičnika, tudi za testiranje. To je le odvračanje pozornosti. Če želite preizkusiti, kakšne odgovore dobite iz strežnika brez filtriranja s strani brskalnika, je bolje, da uporabitecurl -H`, kot je navedeno zgoraj.

Glede kode JavaScript za zahtevo fetch(...) v vprašanju:

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

Odstranite te vrstice. Glave Access-Control-Allow-* so glave odgovora. Nikoli jih ne želite poslati v zahtevi. Edini učinek, ki ga bo to imelo, je ta, da bo brskalnik sprožil predhodno preverjanje.

Komentarji (8)

Ta napaka se pojavi, če se URL odjemalca in URL strežnika ne ujemata, vključno s številko vrat. V tem primeru morate svoji storitvi omogočiti CORS, ki je navzkrižna izmenjava virov izvora.

Če gostite storitev Spring REST, jo lahko najdete v objavi na blogu CORS support in Spring Framework.

Če gostite storitev, ki uporablja strežnik Node.js, potem

  1. Ustavite strežnik Node.js.

  2. npm install cors --save

  3. V svoj strežnik.js dodajte naslednje vrstice

    var cors = require('cors')

    app.use(cors()) // To uporabite po deklaraciji spremenljivke

Komentarji (4)

Odstranite to:

credentials: 'include',
Komentarji (0)