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
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.
Ta odgovor zajema veliko področij, zato je razdeljen na tri dele:
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
https://example.com
.https://example.com
.Access-Control-Allow-Origin
.Access-Control-Allow-Origin
tisto, kar vidi brskalnik.
Z uporabo kode iz https://github.com/Rob--W/cors-anywhere/.<br> lahko preprosto zaženete svoj posrednik;
Svoj proxy lahko tudi enostavno namestite na Heroku v dobesedno samo 2-3 minutah, in sicer s petimi ukazi:git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
https://cors-anywhere.herokuapp.com
, namesto tega predpono uporabite URL za vašo lastno instanco; npr. https://cryptic-headland-94862.herokuapp.com/https://example.com.
Če torej, ko poskušate uporabiti httpsOPTIONS
- ker v tem primeru posrednik pošlje nazaj tudi glave Access-Control-Allow-Headers
in Access-Control-Allow-Methods
, potrebne za uspešno izvedbo preflight.Kako se izogniti predhodnemu preverjanju CORS
Koda v vprašanju sproži predpregled CORS, saj pošlje glavo Authorization
.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Tudi brez tega bi naslov Content-Type: application/json
prav tako sprožil predobdelavo.
Kaj pomeni "preflight": preden brskalnik poskusi POST
v kodi v vprašanju, bo najprej poslal zahtevo OPTIONS
strežniku - da bi ugotovil, ali se strežnik strinja s sprejemanjem navzkrižnega POST
, ki vključuje glavi Authorization
in Content-Type: application/json
.
Deluje precej dobro z majhno skripto curl - dobim svoje podatke. Za pravilno testiranje z
curl
morate posnemati zahtevoOPTIONS
, 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:
Authorization
, temveč bi se (na primer) zanašal na podatke o avtentikaciji, vgrajene v telo zahteve POST
ali kot parameter poizvedbePOST
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 JSONKako 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, torej
http://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 zahteve
Originin jo ponovi/odrazi nazaj v vrednost glave odgovora
Access-Control-Allow-Origin`. Na primer z nginxom: jezik: lang-none -->
add_header Access-Control-Allow-Origin $http_origin
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 glave
Access-Control-Allow-Originodgovora na dejanski izvor vaše kode JavaScript v sprednjem delu, torej na
http://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 uporabite
curl -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.
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
Ustavite strežnik Node.js.
npm install cors --save
V svoj strežnik.js dodajte naslednje vrstice
var cors = require('cors')
app.use(cors()) // To uporabite po deklaraciji spremenljivke