Ik'probeer wat gegevens op te halen uit de REST API van HP Alm. Het werkt vrij goed met een klein curl script - ik krijg mijn gegevens.
Nu lijkt dat doen met JavaScript, fetch en ES6 (min of meer) een groter probleem te zijn. Ik krijg steeds deze foutmelding:
Fetch API cannot load
. Antwoord op preflight verzoek komt niet pass access control check: Geen 'Access-Control-Allow-Origin' header is aanwezig op de aangevraagde bron. Origin 'http://127.0.0.1:3000' is daarom geen toegang toegestaan. Het antwoord had HTTP status code 501. Als een ondoorzichtige respons uw behoeften dient, zet dan het verzoek's mode op 'no-cors' om de bron op te halen met CORS uitgeschakeld.
Ik begrijp dat dit komt omdat ik die gegevens probeer op te halen vanaf mijn localhost en de oplossing zou CORS moeten gebruiken. Nu dacht ik dat ik dat gedaan had, maar op de een of andere manier negeert het wat ik in de header schrijf of is het probleem iets anders?
Dus, is er een implementatie probleem? Doe ik het verkeerd? Ik kan de server logs helaas niet controleren. Ik'm echt een beetje vast hier.
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));
}
Ik gebruik Chrome. Ik heb ook geprobeerd die Chrome CORS Plugin te gebruiken, maar dan krijg ik weer een foutmelding:
De waarde van de 'Access-Control-Allow-Origin' header in het antwoord mag niet het jokerteken '*' zijn als de credentials-modus van het verzoek'is 'include'. Origin 'http://127.0.0.1:3000' is daarom niet toegestaan toegang. De credentials-modus van verzoeken die worden geïnitieerd door de XMLHttpRequest wordt geregeld door het withCredentials attribuut.
Dit antwoord is veelomvattend, dus het is verdeeld in drie delen:
Hoe gebruik je een CORS proxy om "No Access-Control-Allow-Origin header " problemen te omzeilen
Als je geen controle hebt over de server waar je frontend JavaScript code een verzoek naartoe stuurt, en het probleem met het antwoord van die server is alleen het ontbreken van de noodzakelijke Access-Control-Allow-Origin
header, dan kun je nog steeds dingen werkend krijgen-door het verzoek via een CORS proxy te laten lopen. Om te laten zien hoe dat werkt, volgt hier eerst wat code die geen CORS proxy gebruikt:
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?"))
De reden dat het catch
blok daar geraakt wordt is, dat de browser voorkomt dat die code toegang krijgt tot het antwoord dat terugkomt van https://example.com
. En de reden waarom de browser dat doet is, dat het antwoord de Access-Control-Allow-Origin
header mist.
Nu, hier is precies hetzelfde voorbeeld, maar dan met een CORS proxy toegevoegd:
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?"))
Note: Als https
https://example.com
.https://example.com
.Access-Control-Allow-Origin
header toe aan het antwoord.Access-Control-Allow-Origin
header is wat de browser ziet.
Je kunt gemakkelijk je eigen proxy draaien met code van https://github.com/Rob--W/cors-anywhere/.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
, laat je deze voor gaan met de URL van je eigen instantie; bijvoorbeeld https://cryptic-headland-94862.herokuapp.com/https://example.com.
Dus als je httpsOPTIONS
verzoek te doen-omdat in dat geval, de proxy ook de Access-Control-Allow-Headers
en Access-Control-Allow-Methods
headers terugstuurt die nodig zijn om de preflight succesvol te maken.Hoe de CORS preflight te vermijden
De code in de vraag triggert een CORS preflight-omdat het een Authorization
header stuurt.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Zelfs zonder dat, zou de Content-Type: application/json
header ook de preflight triggeren.
Wat "preflight" betekent: voordat de browser de POST
in de code in de vraag probeert, zal het eerst een OPTIONS
verzoek naar de server sturen - om te bepalen of de server opt-in is voor het ontvangen van een cross-origin POST
die de Authorization
en Content-Type: application/json
headers bevat.
Het werkt vrij goed met een klein curl script - Ik krijg mijn data. Om goed te testen met
curl
, moet je het preflightOPTIONS
verzoek emuleren dat de browser stuurt:
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"
...met https://the.sign_in.url
vervangen door wat je eigenlijke sign_in
URL ook is.
Het antwoord dat de browser moet zien van dat OPTIONS
verzoek moet headers bevatten zoals deze:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Als het OPTIONS
antwoord deze headers niet bevat, dan zal de browser daar stoppen en niet eens proberen om het POST
verzoek te versturen. Ook moet de HTTP status code voor het antwoord een 2xx-typisch 200 of 204 zijn. Als het een andere status code is, zal de browser daar stoppen.
De server in de vraag reageert op het OPTIONS
verzoek met een 501 status code, wat blijkbaar betekent dat hij probeert aan te geven dat hij geen ondersteuning heeft voor OPTIONS
verzoeken. Andere servers reageren in dit geval met een 405 "Methode niet toegestaan" status code.
Dus je zult nooit in staat zijn om POST
verzoeken rechtstreeks naar die server te sturen vanuit je frontend JavaScript code als de server op dat OPTIONS
verzoek reageert met een 405 of 501 of iets anders dan een 200 of 204 of als hij niet reageert met die noodzakelijke response headers.
De manier om het triggeren van een preflight te vermijden voor het geval in de vraag zou zijn:
Authorization
request header nodig heeft maar in plaats daarvan (bijvoorbeeld) vertrouwt op authenticatie gegevens ingebed in de body van het POST
verzoek of als een query parameterPOST
body een Content-Type: application/json
media type heeft, maar in plaats daarvan de POST
body accepteert als application/x-www-form-urlencoded
met een parameter genaamd json
(of wat dan ook) waarvan de waarde de JSON data isHoe los ik "Access-Control-Allow-Origin header must not be the wildcard " problemen op
Ik krijg een andere foutmelding:
De waarde van de 'Access-Control-Allow-Origin' header in het antwoord mag niet het jokerteken '' zijn als de credentials-modus van het verzoek's is 'include'. Origin 'http://127.0.0.1:3000' is daarom niet toegestaan toegang. De credentials-modus van verzoeken geïnitieerd door de XMLHttpRequest wordt geregeld door het withCredentials attribuut. Voor een verzoek dat geloofsbrieven bevat, zullen browsers je frontend JavaScript code geen toegang geven tot het antwoord als de waarde van de
Access-Control-Allow-Origin
response header `is. In plaats daarvan moet de waarde in dat geval exact overeenkomen met de oorsprong van je frontend code,
http://127.0.0.1:3000. Zie [*Credentialed requests and wildcards*][1] in het MDN HTTP access control (CORS) artikel. Als je controle hebt over de server waar je het verzoek naar toe stuurt, dan is een gebruikelijke manier om met dit geval om te gaan de server zo in te stellen dat hij de waarde van de
Originrequest header neemt, en die terug echoot/reflecteert in de waarde van de
Access-Control-Allow-Origin` response header. Bijvoorbeeld, met nginx:
add_header Access-Control-Allow-Origin $http_origin
Ik gebruik Chrome. Ik heb ook geprobeerd die Chrome CORS Plugin te gebruiken Die Chrome CORS plugin injecteert blijkbaar gewoon op een simpele manier een
Access-Control-Allow-Origin: *
header in het antwoord dat de browser ziet. Als de plugin slimmer zou zijn, zou hij de waarde van die valseAccess-Control-Allow-Origin
header instellen op de werkelijke oorsprong van je frontend JavaScript code,http://127.0.0.1:3000
. Dus vermijd het gebruik van die plugin, zelfs voor testen. Het is gewoon een afleiding. Als je wilt testen welke antwoorden je van de server krijgt zonder dat de browser ze filtert, kun je betercurl -H
gebruiken zoals hierboven.Wat betreft de frontend JavaScript code voor het
fetch(...)
verzoek in de vraag:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Verwijder deze regels. De Access-Control-Allow-*
headers zijn response headers. Je wilt ze nooit in een request sturen. Het enige effect dat dat heeft is dat de browser een preflight uitvoert.
Deze fout treedt op wanneer de client URL en de server URL niet overeenkomen, inclusief het poortnummer. In dit geval moet u uw service inschakelen voor CORS, dat is cross origin resource sharing.
Als je een Spring REST service host dan kun je deze vinden in de blog post CORS support in Spring Framework.
Als u hosting een service met behulp van een Node.js server dan
Stop de Node.js server.
npm install cors --save
Voeg de volgende regels toe aan uw server.js
var cors = require('cors')
app.use(cors()) // Gebruik dit na de variabele declaratie