Diese Antwort ist sehr umfangreich und besteht aus drei Teilen:
- So verwenden Sie einen CORS-Proxy, um Probleme mit dem Header "Keine Zugriffssteuerung, Zulassen des Ursprungs" zu umgehen
- So vermeiden Sie den CORS-Preflight
- So beheben Sie das Problem "Access-Control-Allow-Origin-Header darf nicht der Platzhalter sein"
So verwenden Sie einen CORS-Proxy, um Probleme mit dem Header "Keine Zugriffssteuerung, Zulassen des Ursprungs" zu umgehen
Wenn Sie den Server nicht steuern, an den Ihr Frontend-JavaScript-Code eine Anfrage sendet, und das Problem mit der Antwort von diesem Server nur das Fehlen des erforderlichen Access-Control-Allow-Origin
Headers ist, können Sie die Dinge trotzdem zum Laufen bringen - indem Sie die Anfrage über a stellen CORS-Proxy. Um zu zeigen, wie das funktioniert, folgt zunächst ein 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, von der er zurückkommt https://example.com
. Der Grund dafür ist, dass der Antwort der Antwortheader fehlt Access-Control-Allow-Origin
.
Hier ist genau das gleiche Beispiel, jedoch nur mit einem hinzugefügten CORS-Proxy:
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://cors-anywhere.herokuapp.com nicht verfügbar oder nicht verfügbar ist, wenn Sie es versuchen, lesen Sie unten, wie Sie Ihren eigenen CORS Anywhere-Server bei Heroku in nur 2-3 Minuten bereitstellen.
Das zweite Code-Snippet oben kann erfolgreich auf die Antwort zugreifen, da die Verwendung der Anforderungs-URL in https://cors-anywhere.herokuapp.com/https://example.com - indem nur die Proxy-URL vorangestellt wird - die Antwort verursacht Anfrage, über diesen Proxy gemacht zu werden, der dann:
- Leitet die Anfrage an weiter
https://example.com
.
- Erhält die Antwort von
https://example.com
.
- Fügt
Access-Control-Allow-Origin
der Antwort den Header hinzu.
- Übergibt diese Antwort mit dem hinzugefügten Header an den anfordernden Frontend-Code.
Der Browser ermöglicht dann dem Frontend-Code den Zugriff auf die Antwort, da diese Antwort mit dem Access-Control-Allow-Origin
Antwortheader vom Browser angezeigt wird.
Sie können Ihren eigenen Proxy einfach mit Code von https://github.com/Rob--W/cors-anywhere/ ausführen .
Sie können auch einfach Ihren eigenen Proxy für Heroku in nur 2-3 Minuten mit 5 Befehlen bereitstellen:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Nachdem Sie diese Befehle ausgeführt haben, wird Ihr eigener CORS Anywhere-Server ausgeführt, z . B. https://cryptic-headland-94862.herokuapp.com/ . Stellen Sie Ihrer Anforderungs-URL also nicht https://cors-anywhere.herokuapp.com
die URL für Ihre eigene Instanz voran, anstatt sie mit einem Präfix zu versehen. Beispiel: https://cryptic-headland-94862.herokuapp.com/https://example.com .
Wenn Sie also versuchen, https://cors-anywhere.herokuapp.com zu verwenden, stellen Sie fest, dass es nicht verfügbar ist (was manchmal der Fall sein wird), sollten Sie ein Heroku-Konto einrichten (falls Sie dies noch nicht getan haben) und 2 nehmen oder 3 Minuten, um die oben genannten Schritte auszuführen und Ihren eigenen CORS Anywhere-Server auf Heroku bereitzustellen.
Unabhängig davon, ob Sie Ihre eigene ausführen oder https://cors-anywhere.herokuapp.com oder einen anderen offenen Proxy verwenden, funktioniert diese Lösung auch dann, wenn die Anforderung Browser dazu veranlasst, eine CORS-Preflight- OPTIONS
Anforderung auszuführen. In diesem Fall ist die Der Proxy sendet auch die Access-Control-Allow-Headers
und Access-Control-Allow-Methods
Header zurück, die für den erfolgreichen Preflight erforderlich sind.
So vermeiden Sie den CORS-Preflight
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 das Content-Type: application/json
würde der Header auch den Preflight auslösen.
Was "Preflight" bedeutet: Bevor der Browser POST
den Code in der Frage versucht, sendet er zuerst eine OPTIONS
Anfrage an den Server, um festzustellen, ob der Server sich dafür entscheidet, einen Cross-Origin zu erhalten POST
, der die Header Authorization
und enthält Content-Type: application/json
.
Es funktioniert ziemlich gut mit einem kleinen Curl-Skript - ich bekomme meine Daten.
Um ordnungsgemäß zu testen curl
, müssen Sie die Preflight- OPTIONS
Anforderung 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 was auch immer Ihre tatsächliche sign_in
URL ist.
Die Antwort, die der Browser auf diese OPTIONS
Anfrage sehen muss , muss folgende Header 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, stoppt der Browser genau dort und versucht nicht einmal, die POST
Anfrage zu senden . Außerdem muss der HTTP-Statuscode für die Antwort 2xx sein - normalerweise 200 oder 204. Wenn es sich um einen anderen Statuscode handelt, stoppt der Browser genau dort.
Der Server in der Frage antwortet auf die OPTIONS
Anfrage mit einem 501-Statuscode, was anscheinend bedeutet, dass er angibt, dass er keine Unterstützung für OPTIONS
Anfragen implementiert . Andere Server antworten in diesem Fall normalerweise mit dem Statuscode 405 "Methode nicht zulässig".
Sie können also niemals POST
Anfragen von Ihrem Frontend-JavaScript-Code direkt an diesen Server stellen, wenn der Server auf diese OPTIONS
Anfrage mit einem 405 oder 501 oder etwas anderem als 200 oder 204 antwortet oder wenn er nicht mit den erforderlichen Antworten antwortet Antwortheader.
Der Weg, um zu vermeiden, dass ein Preflight für den Fall in der Frage ausgelöst wird, wäre:
- Wenn der Server keinen
Authorization
Anforderungsheader benötigte, sondern sich (zum Beispiel) auf Authentifizierungsdaten stützte, die im Hauptteil der POST
Anforderung oder als Abfrageparameter eingebettet waren
- Wenn der Server nicht verlangt hat, dass der
POST
Body einen Content-Type: application/json
Medientyp hat, sondern den POST
Body wie application/x-www-form-urlencoded
mit einem Parameter namens json
(oder was auch immer) akzeptiert, dessen Wert die JSON-Daten sind
So beheben Sie das Problem "Access-Control-Allow-Origin-Header darf nicht der Platzhalter sein"
Ich erhalte eine weitere Fehlermeldung:
Der Wert des Headers 'Access-Control-Allow-Origin' in der Antwort darf nicht der Platzhalter '*' sein, wenn der Anmeldeinformationsmodus der Anforderung 'include' ist. Origin ' http://127.0.0.1:3000 ' ist daher kein Zugriff gestattet. Der Anmeldeinformationsmodus von Anforderungen, die von XMLHttpRequest initiiert wurden, wird durch das Attribut withCredentials gesteuert.
Bei einer Anfrage mit Anmeldeinformationen lassen Browser Ihren Frontend-JavaScript-Code nicht auf die Antwort zugreifen, wenn der Wert des Access-Control-Allow-Origin
Antwortheaders lautet *
. Stattdessen muss der Wert in diesem Fall genau mit dem Ursprung Ihres Frontend-Codes übereinstimmen http://127.0.0.1:3000
.
Siehe Anforderungen und Platzhalter für Anmeldeinformationen im Artikel zur MDN-HTTP-Zugriffssteuerung (CORS).
Wenn Sie den Server steuern, an den Sie die Anforderung senden, können Sie diesen Fall häufig so konfigurieren, dass der Wert des Origin
Anforderungsheaders übernommen und in den Wert des Access-Control-Allow-Origin
Antwortheaders zurückgeführt wird. Zum Beispiel mit nginx:
add_header Access-Control-Allow-Origin $http_origin
Aber das ist nur ein Beispiel; Andere (Web-) Serversysteme bieten ähnliche Möglichkeiten, um Ursprungswerte wiederzugeben.
Ich benutze Chrome. Ich habe auch versucht, dieses Chrome CORS-Plugin zu verwenden
Dieses Chrome CORS-Plugin fügt anscheinend einfach einen Access-Control-Allow-Origin: *
Header in die Antwort ein, die der Browser sieht. Wenn das Plugin intelligenter wäre, würde es den Wert dieses gefälschten Access-Control-Allow-Origin
Antwortheaders auf den tatsächlichen Ursprung Ihres Frontend-JavaScript-Codes setzen http://127.0.0.1:3000
.
Vermeiden Sie es daher, dieses Plugin auch zum Testen zu verwenden. Es ist nur eine Ablenkung. Wenn Sie testen möchten, welche Antworten Sie vom Server erhalten, ohne dass ein Browser sie filtert, sollten Sie curl -H
wie oben beschrieben verwenden.
Soweit der Frontend-JavaScript-Code für die fetch(…)
Anfrage in der Frage:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Entfernen Sie diese Linien. Die Access-Control-Allow-*
Header sind Antwort - Header. Sie möchten sie niemals in einer Anfrage senden. Der einzige Effekt besteht darin, einen Browser für einen Preflight auszulösen.