CORS erklärt: Preflight, Header und CORS-Fehler beheben
CORS erklärt
CORS erklärt: Preflight, Header, Fehler und Lösungen | We.Inc
So funktioniert CORS: einfache Requests vs. Preflight, alle Access-Control-Header, Regeln für Credentials, die häufigsten Konsolenfehler und ein Server-Fix für Express, Next.js und nginx.
CORS (Cross-Origin Resource Sharing) ist der Weg, über den ein Server dem Browser mitteilt, dass JavaScript von einem anderen Origin seine Antworten lesen darf. Der Server antwortet mit Access-Control-Allow-Origin und verwandten Headern. Requests mit anderen Methoden, eigenen Headern oder JSON-Bodys senden zuerst einen OPTIONS-Preflight. Die Lösung gehört immer auf den Server, den du aufrufst, niemals in die Seite.
Die CORS-Response-Header auf einen Blick
Header
Was er erlaubt
Access-Control-Allow-Origin
Welcher Origin die Antwort lesen darf (ein Origin oder *)
Access-Control-Allow-Methods
Methoden, die nach einem Preflight erlaubt sind
Access-Control-Allow-Headers
Request-Header, die nach einem Preflight erlaubt sind
Access-Control-Allow-Credentials
Cookies und Auth-Daten, die mit dem Request gesendet werden (Wert muss true sein)
Access-Control-Expose-Headers
Response-Header, die das Skript lesen darf
Access-Control-Max-Age
Sekunden, die eine Preflight-Antwort gecacht werden darf
Ein CORS-Fehler sieht aus, als wäre dein Code kaputt, dabei hat der Request den Server meist ganz normal erreicht. Der Browser hat sich lediglich geweigert, die Antwort an dein Skript zu übergeben. Mit dem Simulator unten beschreibst du einen Request und eine Server-Konfiguration und siehst dann, ob ein Preflight ausgelöst wird, ob der Browser die Antwort durchlässt und welche Konsolenmeldung du erhalten würdest.
Lege den Origin der Seite, die Methode, einen eigenen Header und fest, ob Cookies gesendet werden.
Lege fest, was der Server antwortet: erlaubter Origin, Methoden, Header und das Credentials-Flag.
Lies das Ergebnis: ob ein Preflight nötig ist, ob er durchgeht und welchen Grund die Konsole bei einem Fehler nennt.
Kopiere das passende Server-Snippet unten und füge es in die API ein, nicht ins Frontend.
Gib den exakt anfragenden Origin aus einer Allowlist zurück, sobald Cookies im Spiel sind, denn die Wildcard wird zusammen mit Credentials abgelehnt.
Füge Vary: Origin hinzu, wenn sich der erlaubte Origin je nach Request ändert, damit Caches nicht die Antwort einer Website an eine andere ausliefern.
Beantworte OPTIONS mit einem 2xx-Status und ohne Redirect. Ein Preflight, der auf einen Login-Redirect trifft, scheitert jedes Mal.
CORS im eigenen Browser abzuschalten versteckt das Problem nur auf deinem Rechner. Deine Besucher bekommen den Fehler trotzdem.
Aufrufe von Server zu Server haben nie etwas mit CORS zu tun. Wenn du die API nicht kontrollierst, rufe sie stattdessen aus deinem eigenen Backend auf.
Häufige Fragen
Warum funktioniert es mit Postman oder curl, aber nicht im Browser?
CORS wird nur von Browsern durchgesetzt, damit die Skripte einer Website nicht mit deinen Cookies die Daten einer anderen Website lesen können. Tools wie curl führen keinen fremden Seitencode aus und ignorieren CORS deshalb. Die Server-Antwort war identisch, nur der Browser hat entschieden, sie zurückzuhalten.
Was löst einen Preflight-Request aus?
Jede Methode außer GET, HEAD oder POST, jeder Header außerhalb der wenigen freigegebenen (Accept, Accept-Language, Content-Language, Content-Type, Range) oder ein anderer Content-Type als Formular-Encoding, multipart oder text/plain. Das Senden von application/json ist der häufigste Auslöser.
Kann ich CORS im Frontend beheben?
Nein. Access-Control-Header in deinem Request zu setzen bewirkt nichts, und mode: no-cors liefert dir eine undurchsichtige Antwort, die dein Skript nicht lesen kann. Entweder fügt die API die Header hinzu, oder dein eigener Server holt die Daten ab und reicht sie weiter.
Kann ich Access-Control-Allow-Origin: * mit Cookies verwenden?
Nein. Wenn ein Request Credentials mitsendet, lehnt der Browser einen Wildcard-Origin ab und verlangt den exakten Origin plus Access-Control-Allow-Credentials: true. Dasselbe gilt für Wildcards in den Listen für Methoden, Header und Expose-Header.
Warum kann mein Skript einen eigenen Response-Header nicht lesen?
Cross-Origin-Skripte sehen standardmäßig nur eine kurze Liste sicherer Response-Header. Trage alle anderen in Access-Control-Expose-Headers ein, zum Beispiel X-Request-Id, dann werden sie lesbar.
Same Origin, und warum der Browser das Lesen blockiert
Ein Origin besteht aus Schema, Host und Port zusammen. https://app.example.com und https://api.example.com sind unterschiedliche Origins, ebenso die http- und die https-Version derselben Domain. Standardmäßig darf ein Skript einen Request an einen anderen Origin senden, aber nicht lesen, was zurückkommt.
CORS ist die ausdrückliche Freigabe. Die API listet auf, welchen Origins sie vertraut, und der Browser setzt diese Liste im Namen des Besuchers durch. Deshalb muss der Header von dem Server kommen, den du aufrufst.
Einfache Requests und Preflights
Ein schlichter GET oder ein POST aus einem normalen Formular geht direkt mit einem Origin-Header raus. Der Browser prüft dann die Antwort auf einen erlaubten Origin, bevor er sie an deinen Code übergibt.
Alles darüber hinaus sendet zuerst einen OPTIONS-Request mit Access-Control-Request-Method und Access-Control-Request-Headers. Nur wenn der Server beides genehmigt, geht der eigentliche Request raus. Mit Access-Control-Max-Age kann sich der Browser die Genehmigung merken, allerdings begrenzen Browser die Dauer.
Den Konsolenfehler lesen
Aus Sicherheitsgründen erfährt dein JavaScript nur, dass der Fetch fehlgeschlagen ist, mit einem TypeError und ohne Details. Der eigentliche Grund steht in der Browser-Konsole und nennt den Header, der gefehlt hat oder falsch war. Gleiche ihn mit der Tabelle der Meldungen unten ab.
Häufige CORS-Fehler und wie du sie behebst
Der Wortlaut der Meldungen unterscheidet sich je nach Browser. Das hier sind die Gründe, wie Firefox sie auf MDN benennt; Chrome sagt dasselbe in längeren Sätzen.
CORS-Gründe in der Konsole und die Lösung auf dem Server
Grund in der Konsole
Was er bedeutet
Lösung auf dem Server
CORS header 'Access-Control-Allow-Origin' missing
Die Antwort enthielt überhaupt keinen Allow-Origin-Header
Füge den Header jeder Antwort hinzu, auch Fehlerantworten
CORS header 'Access-Control-Allow-Origin' does not match
Der Header nennt einen anderen Origin
Gib den Origin des Aufrufers aus deiner Allowlist zurück
Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'
Es wurden Cookies gesendet, aber der Server hat mit * geantwortet
Gib den exakten Origin und Allow-Credentials: true zurück
expected 'true' in CORS header 'Access-Control-Allow-Credentials'
Credentials gesendet, aber das Flag fehlt
Sende Access-Control-Allow-Credentials: true
Did not find method in CORS header 'Access-Control-Allow-Methods'
Der Preflight hat die Methode nicht genehmigt
Trage PUT, PATCH oder DELETE in Allow-Methods ein
missing token in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel
Ein Request-Header wie Authorization wurde nicht genehmigt
Trage ihn in Allow-Headers ein
CORS preflight channel did not succeed
OPTIONS ist fehlgeschlagen, wurde umgeleitet oder hat einen Fehler geliefert
Beantworte OPTIONS mit 204 und den Headern
Multiple CORS header 'Access-Control-Allow-Origin' not allowed
Zwei Ebenen (App und Proxy) haben den Header beide gesetzt
Setze ihn nur an einer Stelle
Server-Snippets
Express: Allowlist mit Credentials
Gibt den Origin nur zurück, wenn er auf der Liste steht, beantwortet Preflights mit 204 und fügt Vary hinzu, damit Caches die Origins auseinanderhalten.
Next.js-Route-Handler
Ein öffentlicher Endpunkt ohne Cookies kann die Wildcard verwenden. Exportiere OPTIONS, damit der Preflight eine eigene Antwort bekommt.
nginx vor einer API
Das Flag always behält den Header auch bei Fehlerantworten bei, sodass ein 500 seinen echten Status zeigt statt eines CORS-Fehlers.
Die Browserseite: Cookies Cross-Origin senden
credentials: "include" ist das, was auf dem Server die strengeren Regeln für Credentials aktiviert.
CORS-Request-Simulator
Beschreibe einen Request und die CORS-Header des Servers, um zu sehen, ob ein Preflight gesendet wird und ob der Browser dein Skript die Antwort lesen lässt.
Der Request
Die Antwort des Servers
Origin der Seite
Origin der API
Methode
Content-Type
Kein Body
Zusätzlicher Request-Header (leer für keinen)
Cookies senden (credentials: include)
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Credentials: true
Ergebnis
Same Origin: CORS greift nicht, die Antwort ist lesbar.
Kein Preflight: Das ist ein einfacher Request.
Preflight nötig: Der Browser sendet zuerst OPTIONS.
Grund: Die Methode ist nicht GET, HEAD oder POST.
Grund: Der Header {v} ist nicht freigegeben.
Grund: Content-Type {v} gehört nicht zu den drei einfachen Typen.