So beheben Sie CORS-Probleme
Wahrscheinlich haben Sie bereits Fehler wie den folgenden in der JavaScript-Konsole Ihres Browsers gesehen, als Sie versuchten, AJAX-Anforderungen auszuführen:
Auf den ersten Blick ist es schwierig zu verstehen, was passiert, und herauszufinden, wo das Problem herkommt. Wir können sicher sein, dass die Fehler mit dem CORS-Mechanismus (Cross-Origin Resource Sharing) zusammenhängen. In diesem Artikel wird beschrieben, wie Sie verstehen, was gerade passiert, und wie Sie solche Probleme beheben.
CORS verstehen
Mit CORS entscheidet die Remote-Webanwendung, ob die Anforderung bearbeitet werden kann. Die CORS-Spezifikation unterscheidet zwei verschiedene Anwendungsfälle:
- Einfache Anfragen . Dieser Anwendungsfall gilt, wenn wir die HTTP-Methoden GET, HEAD und POST verwenden. Im Fall von POST - Methoden, nur Inhaltstypen mit den folgenden Werten werden unterstützt:
text/plain
, und .application/x-www-form-
urlencoded multipart/form-data
- Preflight-Anforderungen . Wenn der Anwendungsfall "Einfache Anforderungen" nicht zutrifft, wird eine erste Anforderung (mithilfe der HTTP OPTIONS-Methode) erstellt, um zu überprüfen, was im Kontext domänenübergreifender Anforderungen möglich ist.
Diese beiden Szenarien wurden von den Entwicklern von CORS erstellt, um alte Webserver zu berücksichtigen, die die Spezifikation nicht unterstützen. Weitere Informationen finden Sie in dieser großartigen Antwort auf der StackOverflow-Website
Beachten Sie, dass einfache Anforderungen automatisch zu Preflight-Anforderungen werden, wenn Sie der Anforderung mithilfe des Authentifizierungsheaders Authentifizierung hinzufügen.
Client und Server tauschen eine Reihe von Headern aus, um das Verhalten in Bezug auf domänenübergreifende Anforderungen festzulegen. Schauen wir sie uns jetzt an. Wir werden dann beschreiben, wie sie in beiden Anwendungsfällen verwendet werden. Beginnen wir mit Überschriften für Anfragen:
- Herkunft : Dieser Header wird vom Client verwendet, um anzugeben, von welcher Domäne aus die Anforderung ausgeführt wird. Der Server verwendet diesen Hinweis, um die domänenübergreifende Anforderung zu autorisieren oder nicht.
- Zugriffssteuerungsanforderungsmethode : Im Kontext von Preflight-Anforderungen sendet die OPTIONS-Anforderung diesen Header, um zu überprüfen, ob die Zielmethode im Kontext domänenübergreifender Anforderungen zulässig ist.
- Access-Control-Request-Headers
: Im Kontext von Preflight-Anfragen sendet die OPTIONS-Anfrage diesen Header, um die Header aufzulisten, die vom Server für die Zielmethode im Kontext domänenübergreifender Anfragen akzeptiert werden.
Fahren wir mit den Überschriften für die Antworten fort:
- Access-Control-Allow-
Credentials : Gibt an, ob Anmeldeinformationen für domänenübergreifende Anforderungen unterstützt werden. - Access-Control-Allow-Methods : Mit diesem Header teilt der Server mit, welche Methoden im Kontext der Anfrage berechtigt sind. Dies wird normalerweise im Kontext von Preflight-Anforderungen verwendet.
- Access-Control-Allow-Origin : Über diesen Header informiert der Server, welche Domains für die Anfrage berechtigt sind.
- Access-Control-Allow-Headers : Über diesen Header informiert der Server, welche Header im Kontext der Anfrage berechtigt sind. Dies wird normalerweise im Kontext von Preflight-Anforderungen verwendet.
Wir haben die wichtigsten CORS-Header aufgelistet. Weitere Informationen zum CORS-Prinzip finden Sie im Mozilla Developer Network .
Nachdem wir die Grundlagen beschrieben haben, wollen wir diese Prinzipien in Browsern in Aktion sehen.
Debuggen von CORS im Browser
Um herauszufinden, was passiert, müssen wir die Tools des Browsers nutzen, um die Fehlermeldung und die ausgetauschten Anfragen und Antworten anzuzeigen. Ohne diese Hinweise ist es schwierig oder sogar unmöglich, den Fehler zu verstehen.
Meistens arbeiten Entwickler mit einem REST-Client wie dem Restlet-Client , um die Interaktionen mit dem Web-API / REST-Service zu testen. Auf dieser Ebene funktionieren Anforderungen im Browser einwandfrei, da Chrome-Erweiterungen bestimmte Berechtigungen in ihrer Konfigurationsdatei (manifest.json) angeben können. Mit dem webRequest können Sie jede Anfrage im Browser über eine Erweiterung ausführen. Hier ist ein Konfigurationsbeispiel:
{
"manifest_version": 2,
"short_name": "My Chrome extension",
(...)
"permissions": [
(...)
"webRequest",
"webRequestBlocking",
"cookies",
"<all_urls>",
(...)
],
(...)
}
Die herkömmlichen clientseitigen Anwendungen können dies nicht und müssen bei der Ausführung domänenübergreifender Anforderungen die CORS-Regeln einhalten. Beachten Sie, dass solche Mechanismen intern vom Browser verarbeitet werden. Auf der Ebene der Anwendung, die im Browser ausgeführt wird, ist nichts zu tun.
Damit alles funktioniert, muss der CORS-Mechanismus richtig implementiert werden, dh Anforderungen und Antworten mit den richtigen Überschriften. Wir werden nun alle diese Börsen detailliert beschreiben.
Einfache Anfragen
Wie zuvor beschrieben, basieren einfache Anforderungen auf einzelnen Anforderungen, dh keinen zusätzlichen OPTIONEN-Anforderungen. Dieser Fall betrifft HTTP-GET-, HEAD-Methoden, in einigen Fällen aber auch die POST-Methode.
Wenn der Browser erkennt, dass sich die AJAX-Anforderung nicht in derselben Domäne wie die aktuelle Seite befindet, sendet er automatisch einen Origin-Header an den Server. Dies soll die CORS-Unterstützung auf dem Server für die Anforderung aktivieren, und der Browser erwartet, dass CORS-Header in der Antwort empfangen werden. Hier ist ein Beispiel:
Hinweis: Zwei Anforderungen mit demselben Host, aber nicht demselben Port, gelten nicht als in derselben Domäne.
Wir werden das gleiche Verhalten mit einer POST-Anfrage haben, die eine Formular-Payload ( Inhaltstyp) sendet :
application/x-www-form-
Stellen Sie sich vor, der Server gibt die CORS-Header (z. B. den Access-Control-Allow-Origin
einen) nicht zurück, und der Browser zeigt die folgenden Fehler in der JavaScript-Konsole an:
Werfen Sie einen Blick auf die Registerkarte Netzwerk, um das Problem zu beheben. Wir können den
Access-Control-Allow-Origin
Header nicht im Bereich "Antwort-Header" finden.
Das Problem liegt nicht in der Client-Anwendung, sondern in der Server-Anwendung. Um dies zu beheben, müssen wir die CORS-Unterstützung auf Serverebene aktivieren.
Einfache Anfragen sind der einfachste Fall für domänenübergreifende Anfragen. Schauen wir uns nun die vorgeprüften an.
Preflight-Anforderungen
Preflight-Anforderungen beinhalten eine zusätzliche OPTIONS-Anforderung, die vom Browser unter der Haube vor der Zielanforderung ausgeführt wird. Wir können sehr einfach in den Preflight-Modus wechseln. Beispielsweise:
- Ändern Sie den Inhaltstyp unserer vorherigen POST-Anforderung von in .
application/x-www-form-
urlencoded application/json
- Verwenden Sie eine HTTP-Methode wie PUT, PATCH oder DELETE
- Fügen Sie einen HTTP-Header wie Authorization for authentication hinzu.
Aus diesem Grund kann der Unterschied zwischen einfachen und vorgeprüften Anforderungen oft unklar sein. Dies könnte hauptsächlich auf die Unterstützung der POST-Methode zurückzuführen sein. Beispielsweise kann Ihre Anwendung für die Übermittlung einer Formularnutzlast ( Inhaltstyp) verwendet werden, jedoch nicht für eine JSON-Datei, wenn der Server die OPTIONS-Methoden nicht ordnungsgemäß verarbeitet.application/x-www-form-
Hier ist ein Beispiel einer Preflight-Anforderung mit der Übermittlung einer JSON-Nutzlast unter Verwendung der POST-Methode:
Hier sind die Details der OPTIONEN-Anfrage:
Es ist wichtig zu beachten, dass wir im Fall einer GET-Methode auch Preflight-Anforderungen haben können. Dies ist der Fall, wenn wir Authorization
der im vorherigen Abschnitt beschriebenen GET-Anforderung einen Header hinzufügen .
In diesem Zusammenhang können mehrere mögliche Fehler auftreten. Werfen wir einen Blick auf die gängigsten und wie man sie behebt.
CORS-Anforderungen / -Optionen sind nicht aktiviert
Der erste Fehler besteht darin, dass OPTIONS-Methoden vom Server nicht unterstützt werden, da sie CORS überhaupt nicht unterstützen oder die Unterstützung minimal ist und Preflight-Anforderungen nicht unterstützt. In diesem Fall wird in der JavaScript-Konsole der folgende Fehler angezeigt:
Wir können feststellen, dass die Nachricht das Fehlen des CORS Access-Control-Allow-Origin
in der Antwort und den HTTP-Statuscode 405 erwähnt. Dieser Statuscode ist ein nützlicher Hinweis, um zu verstehen, dass der Server keine OPTIONS-Anforderungen unterstützt. Werfen wir einen Blick auf die Registerkarte Netzwerk:
Wir können feststellen, dass bei einem 4xx-Statuscode dasselbe Problem auftritt. Die Möglichkeit, dieses Problem zu beheben, besteht aus:
- Fügen Sie die Unterstützung der OPTIONS-Methode hinzu, damit CORS-Preflight-Anforderungen gültig sind
- Fügen Sie den
Access-Control-Allow-Origin
Header in Ihre Antwort ein, damit der Browser die Gültigkeit der Anforderung überprüfen kann
Anforderungsheader werden nicht unterstützt
Ein weiterer Fehler könnte sein, dass Header, die wir in unserer Anfrage verwenden möchten (z. B. Content-Type
oder
Authorization
), in der vorgeprüften CORS-Antwort unter Verwendung des Access-Control-Allow-Headers
Headers nicht aktiviert sind . In diesem Fall wird der folgende Fehler angezeigt:
In der entsprechenden Preflight-Anforderung sehen wir, dass Access-Control-Allow-Headers
in der Antwort kein Header zurückgegeben wird, während die Zielanforderung den Content-Type
Header verwenden möchte :
Um dieses Problem zu beheben, fügen Sie einfach den entsprechenden Header auf der Serverseite hinzu, wenn Sie die OPTIONS-Methode verwenden. Wir werden dann folgende Anfragen haben:
Nicht authentifizierte OPTIONS-Anforderung
Ein weiteres häufiges Problem ist mit der Verwendung des Authorization
Headers verbunden. Das Ungewöhnliche ist, dass dieser Header nicht innerhalb der Preflight-Anforderung gesendet wird. Wenn die Serveranwendung versucht, alle Anforderungen, auch die vorgeprüften, zu authentifizieren, wird ein "nicht autorisierter" Fehler mit dem 401-Statuscode angezeigt:
Der Server muss repariert werden, damit er Preflight-Anforderungen nicht authentifiziert. Danach würden wir die folgenden Anfragen sehen:
Probleme beheben
In diesem Abschnitt werden die möglichen Lösungen für die Behebung von CORS-Problemen je nach Kontext beschrieben.
Aktualisieren des Servers
Meistens besteht die einfachste Möglichkeit, das Problem zu beheben, darin, den Server zu aktualisieren. Die meisten serverseitigen Technologien bieten Unterstützung für die schnelle Konfiguration von CORS. Bei Node und ExpressJS besteht dies beispielsweise nur darin, die CORS-Middleware zu installieren und sie beim Initialisieren der Express-Anwendung zu verwenden:
var express = require('express')
, cors = require('cors')
, app = express();
app.use(cors());
(...)
In einigen Fällen handelt es sich bei dem Zieldienst um einen Drittanbieter, und die Aktualisierung zur Unterstützung von CORS kann nicht durchgeführt werden. Es müssen nun mehrere Ansätze in Betracht gezogen werden.
JSONP
Der erste ist JSONP. Diese Technik wird seit langem für Onlinedienste und domänenübergreifende Anforderungen verwendet, muss jedoch von den Remotediensten verwendet werden. Es besteht aus dem dynamischen Hinzufügen eines Skriptelements zur HTML-Seite, um die Anforderung auszuführen. Wenn die Antwort empfangen wird, wird der entsprechende Code analysiert und als JavaScript ausgeführt.
Aus diesem Grund muss der Antwortinhalt das folgende Format haben:
callbackName([ { name: ‘some value' }, { name: ‘some other value' }])
Der Name des Rückrufs wird als Parameter der Anforderung angegeben. In den meisten Fällen lautet der Name des Rückrufparameters gemäß Konvention callback
oder c
. Hier ist eine Beispielanfrage:
http://somehost/resource/
someid?callback=callbackName
Wir können feststellen, dass ein solcher Ansatz Nachteile und Einschränkungen aufweist, da nur GET-Methoden unterstützt werden und Payload nur als Abfrageparameter bereitgestellt werden kann.
Service-Proxy
Die letzte verbleibende Möglichkeit besteht darin, einen Proxy auf der Serverseite in Ihrer Anwendung hinzuzufügen, dies erfordert jedoch ein wenig Arbeit. Wir können jedoch feststellen, dass Ionic Proxy über seine Konfigurationsdatei ionic.config.json unterstützt:
(...)
"proxies": [{
"path": "/yelp/v3/businesses",
"proxyUrl": "https://api.yelp.com/v3/businesses "
}]
(...)
CORS- und Web-APIs
Da Web-APIs auf die Kommunikation zwischen Anwendungen abzielen, unterstützen sie CORS die meiste Zeit sofort. Dies ist der Fall bei Restlet Cloud, unserer Plattform zum Implementieren und Hosten von Web-APIs.
Beispiel: Bei einer Anforderung zum Abrufen aller Kontakte eines Geschäfts mithilfe einer Web-API (die mit dem Schnellstart-Assistenten erstellt wurde) wird die entsprechende Preflight-Anforderung von Cloud automatisch verarbeitet, wie nachfolgend beschrieben:
Eine interessante Funktion ist die Unterstützung von CORS für Dateien, da die meisten statischen Webserver diese Spezifikation beim Bereitstellen von Dateien nicht unterstützen. Mit Restlet Cloud können wir einen Dateispeicher in einer Web-API verfügbar machen und haben in diesem Kontext Zugriff auf die CORS-Unterstützung.
Fazit
Wie im gesamten Artikel beschrieben, zielt CORS auf domänenübergreifende Anforderungen ab und verfügt über spezifische Mechanismen, deren Debugging schwierig sein kann. Dies ist hauptsächlich auf Preflight-Anforderungen zurückzuführen, die in einigen Fällen verwendet werden und eine zusätzliche OPTIONS-Anforderung beinhalten.