Ich versuche, einige Daten von der REST-API von HP Alm zu holen. Es funktioniert ziemlich gut mit einem kleinen Curl-Skript - ich bekomme meine Daten.
Jetzt tun, dass mit JavaScript, fetch und ES6 (mehr oder weniger) scheint ein größeres Problem zu sein. Ich bekomme immer wieder diese Fehlermeldung:
Fetch API kann
nicht laden. Antwort auf Preflight-Anforderung doesn't pass access control check: Kein 'Access-Control-Allow-Origin' Header ist auf der angeforderten Ressource vorhanden. Herkunft 'http://127.0.0.1:3000' ist daher ist der Zugriff nicht erlaubt. Die Antwort hatte den HTTP-Statuscode 501. Wenn eine undurchsichtige Antwort Ihren Bedürfnissen entspricht, setzen Sie den Modus der Anfrage auf 'no'. 'no-cors', um die Ressource mit deaktiviertem CORS abzurufen.
Ich verstehe, dass dies daran liegt, dass ich versuche, die Daten von meinem localhost abzurufen, und die Lösung sollte CORS verwenden. Ich dachte, ich hätte das getan, aber irgendwie ignoriert es entweder, was ich in den Header schreibe, oder das Problem ist ein anderes?
Gibt es also ein Implementierungsproblem? Mache ich es falsch? Ich kann die Server-Logs leider nicht überprüfen. Ich bin wirklich ein bisschen stecken 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));
}
Ich verwende Chrome. Ich habe auch versucht, das Chrome CORS Plugin zu verwenden, aber dann bekomme ich eine andere Fehlermeldung:
Der Wert des 'Access-Control-Allow-Origin' Headers in der Antwort darf nicht der Platzhalter '*' sein, wenn der Anmeldemodus der Anfrage'ist 'include'. Herkunft 'http://127.0.0.1:3000' ist daher nicht erlaubt Zugriff. Der Anmeldeinformationsmodus von Anfragen, die von der XMLHttpRequest eingeleitet werden, wird durch das Attribut withCredentials gesteuert.
Diese Antwort deckt sehr viel ab und ist daher in drei Teile gegliedert:
Verwendung eines CORS-Proxys zur Umgehung von "Kein Access-Control-Allow-Origin-Header "-Problemen Wenn Sie keine Kontrolle über den Server haben, an den Ihr Frontend-JavaScript-Code eine Anfrage sendet, und das Problem mit der Antwort dieses Servers nur darin besteht, dass der erforderliche "Access-Control-Allow-Origin"-Header fehlt, können Sie die Dinge trotzdem zum Laufen bringen, indem Sie die Anfrage über einen CORS-Proxy stellen. Um zu zeigen, wie das funktioniert, hier zunächst etwas Code, der keinen CORS-Proxy verwendet:
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?"))
Der Grund, warum der catch
-Block dort getroffen wird, ist, dass der Browser verhindert, dass dieser Code auf die Antwort zugreift, die von https://example.com
zurückkommt. Und der Grund, warum der Browser das tut, ist, dass der Antwort der Access-Control-Allow-Origin
Response Header fehlt.
Hier ist genau das gleiche Beispiel, aber nur mit einem CORS-Proxy hinzugefügt:
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?"))
Hinweis: Wenn https
https://example.com
weiterleitet.https://example.com
empfängt.Access-Control-Allow-Origin
Header zur Antwort hinzu.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
voranzustellen, stellen Sie ihr stattdessen die URL für Ihre eigene Instanz voran, z.B. https://cryptic-headland-94862.herokuapp.com/https://example.com.
Wenn Sie also versuchen, httpsWie kann man den CORS-Preflight vermeiden
Der Code in der Frage löst einen CORS-Preflight aus, da er einen Authorization
-Header sendet.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Auch ohne diesen würde der Content-Type: application/json
-Header den Preflight auslösen.
Was "preflight" bedeutet: bevor der Browser den POST
im Code in der Frage ausprobiert, sendet er zunächst eine OPTIONS
-Anfrage an den Server - um festzustellen, ob der Server dem Empfang eines herkunftsübergreifenden POST
zustimmt, der die Header Authorization
und Content-Type: application/json
enthält.
Es funktioniert ziemlich gut mit einem kleinen Curl-Skript - ich erhalte meine Daten.
Um mit curl
richtig zu testen, müssen Sie die Preflight-OPTIONS-Anfrage emulieren, die der Browser sendet:
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"
...mit https://the.sign_in.url
ersetzt durch Ihre tatsächliche sign_in
URL.
Die Antwort, die der Browser von dieser OPTIONS
-Anfrage sehen muss, muss Kopfzeilen wie diese enthalten:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Wenn die "OPTIONS"-Antwort diese Header nicht enthält, bricht der Browser an dieser Stelle ab und versucht erst gar nicht, die "POST"-Anfrage zu senden. Außerdem muss der HTTP-Statuscode für die Antwort ein 2xx sein - typischerweise 200 oder 204. Bei jedem anderen Statuscode bricht der Browser an dieser Stelle ab. Der fragliche Server antwortet auf die "OPTIONS"-Anfrage mit einem 501-Statuscode, was offensichtlich bedeutet, dass er versucht, anzuzeigen, dass er keine Unterstützung für "OPTIONS"-Anfragen bietet. Andere Server antworten in diesem Fall in der Regel mit einem 405-Statuscode "Method not allowed". Sie werden also niemals in der Lage sein, von Ihrem Frontend-JavaScript-Code aus direkt "POST"-Anfragen an diesen Server zu stellen, wenn der Server auf diese "OPTIONS"-Anfrage mit einem 405 oder 501 oder etwas anderem als einem 200 oder 204 antwortet oder wenn er nicht mit den erforderlichen Antwort-Headern antwortet. Der Weg, um zu vermeiden, dass ein Preflight für den Fall in der Frage ausgelöst wird, wäre:
POST
-Body einen Content-Type: application/json
-Medientyp hat, sondern stattdessen den POST
-Body als application/x-www-form-urlencoded
mit einem Parameter namens json
(oder was auch immer) akzeptiert, dessen Wert die JSON-Daten sindWie behebe ich das "Access-Control-Allow-Origin-Header darf nicht der Platzhalter sein " Problem Ich erhalte eine weitere Fehlermeldung:
Der Wert des 'Access-Control-Allow-Origin' Headers in der Antwort darf nicht der Platzhalter '' sein, wenn der Anmeldemodus der Anfrage'ist 'include'. Herkunft 'http://127.0.0.1:3000' ist daher nicht erlaubt Zugriff. Der Credentials-Modus von Anfragen, die von der XMLHttpRequest eingeleitet werden, wird durch das Attribut withCredentials gesteuert. Bei einer Anfrage, die Anmeldeinformationen enthält, lassen die Browser Ihren Frontend-JavaScript-Code nicht auf die Antwort zugreifen, wenn der Wert des Antwort-Headers "Access-Control-Allow-Origin" "" lautet. Stattdessen muss der Wert in diesem Fall genau mit der Herkunft Ihres Frontend-Codes übereinstimmen, nämlich
http://127.0.0.1:3000
. Siehe Credentialed requests and wildcards im MDN-Artikel HTTP-Zugangskontrolle (CORS). Wenn Sie die Kontrolle über den Server haben, an den Sie die Anfrage senden, dann ist eine übliche Methode, mit diesem Fall umzugehen, den Server so zu konfigurieren, dass er den Wert desOrigin
-Anfrage-Headers nimmt und diesen in den Wert desAccess-Control-Allow-Origin
-Antwort-Headers zurückspiegelt. Zum Beispiel, mit nginx:
add_header Access-Control-Allow-Origin $http_origin
Ich verwende Chrome. Ich habe auch versucht, das Chrome CORS Plugin zu verwenden Das Chrome CORS-Plugin fügt anscheinend einfach einen
Access-Control-Allow-Origin: *" in die Antwort, die der Browser sieht. Wäre das Plugin schlauer, würde es den Wert dieses gefälschten "Access-Control-Allow-Origin"-Headers auf den tatsächlichen Ursprung Ihres Frontend-JavaScript-Codes, "http://127.0.0.1:3000", setzen. Vermeiden Sie es also, dieses Plugin zu verwenden, selbst zu Testzwecken. Es ist nur eine Ablenkung. Wenn Sie testen wollen, welche Antworten Sie vom Server erhalten, ohne dass der Browser sie filtert, sind Sie besser dran, wenn Sie
curl -H` wie oben verwenden.Was den Frontend-JavaScript-Code für die
fetch(...)
-Anfrage in der Frage angeht:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Entfernen Sie diese Zeilen. Die Access-Control-Allow-*
-Header sind Antwort-Header. Sie sollten sie niemals in einer Anfrage senden. Der einzige Effekt, den sie haben, ist, dass sie einen Browser dazu bringen, einen Preflight durchzuführen.
Dieser Fehler tritt auf, wenn die Client-URL und die Server-URL nicht übereinstimmen, auch nicht die Portnummer. In diesem Fall müssen Sie Ihren Dienst für CORS aktivieren, was Cross Origin Resource Sharing bedeutet.
Wenn Sie einen Spring REST-Dienst hosten, können Sie dies im Blogpost CORS-Unterstützung in Spring Framework nachlesen.
Wenn Sie einen Dienst mit einem Node.js-Server hosten, dann
Stoppen Sie den Node.js-Server.
npm install cors --save".
Fügen Sie folgende Zeilen in Ihre server.js ein
var cors = require('cors')
app.use(cors()) // Verwenden Sie dies nach der Variablendeklaration
Entfernen Sie dies:
credentials: 'include',