So behebst du CORS-Fehler (und warum sie entstehen)
Ein CORS-Fehler bedeutet, dass deine Webseite versucht hat, eine Antwort von einem anderen Ursprung (einer anderen Domain, einem anderen Port oder Protokoll) zu lesen, und dieser Server keine Header gesendet hat, die das erlauben. Browser blockieren die Antwort zum Schutz der Nutzer. Du behebst es auf dem Server, indem du einen Access-Control-Allow-Origin-Header für den Ursprung deiner Website zurückgibst und OPTIONS-Preflight-Anfragen beantwortest, oder du umgehst es, indem du die Anfrage über dein eigenes Backend auf demselben Ursprung schickst.
Es ist einer der verwirrendsten Fehler der Webentwicklung, weil die Anfrage oft beim Server ankommt. Dieser Leitfaden erklärt, was passiert, und wie du jede Variante behebst.
Was „Ursprung“ bedeutet
Ein Ursprung ist die Kombination aus Protokoll, Domain und Port:
| URL | Ursprung |
|---|---|
https://myapp.com/dashboard | https://myapp.com |
https://api.myapp.com/users | https://api.myapp.com (anderer Subdomain, also anderer Ursprung) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (anderer Port, also anderer Ursprung) |
Browser folgen der Same-Origin-Policy: JavaScript auf einer Seite darf Antworten vom eigenen Ursprung frei lesen, von anderen aber nicht. CORS (Cross-Origin Resource Sharing) ist das System, mit dem ein Server zustimmt: „Antworten von mir dürfen von Seiten dieser Ursprünge gelesen werden.“
Zwei Dinge überraschen viele Leute:
- Die Anfrage erreicht oft den Server. CORS verhindert meist, dass dein Code die Antwort liest, nicht, dass der Server die Anfrage empfängt. Ein POST wurde unter Umständen gespeichert, obwohl du einen Fehler gesehen hast.
- Nur Browser setzen es durch. curl, Postman und serverseitiger Code ignorieren CORS vollständig. Dass etwas „in Postman funktioniert“, sagt daher nichts über CORS aus.
Schritt 1: Den genauen Fehler lesen
Öffne die Entwicklertools (Rechtsklick → Untersuchen), wechsle zur Konsole und lies die vollständige Meldung. Die Formulierung in Chrome verrät dir, welches Problem vorliegt:
| Meldung enthält | Was falsch ist |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Der Server hat den Header gar nicht gesendet, oder die Anfrage ist gescheitert, bevor sie deinen CORS-Code erreichte (etwa ein 404 oder 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Der Server erlaubt einen anderen Ursprung als deinen |
Response to preflight request doesn't pass access control check | Die OPTIONS-Preflight-Anfrage ist fehlgeschlagen |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Du sendest Cookies, und der Server hat mit * geantwortet |
Request header field authorization is not allowed | Der Server hat diesen Header nicht in Access-Control-Allow-Headers aufgeführt |
Öffne dann den Tab Netzwerk, finde die fehlgeschlagene Anfrage (und jede OPTIONS-Anfrage davor) und prüfe ihren Statuscode und die Antwort-Header.
Prüfe zuerst den Statuscode. Viele „CORS-Fehler“ sind in Wahrheit ein Serverfehler in Verkleidung. Stürzt der Server ab oder liefert er einen 404, fehlen in seiner Fehlerantwort oft die CORS-Header, und der Browser meldet CORS statt des eigentlichen Problems. Behebe den 500 oder 404, und der CORS-Fehler verschwindet womöglich.
Schritt 2: Entscheiden, ob der Browser diese API überhaupt direkt aufrufen sollte
Bevor du Header hinzufügst, frag dich: Sollte der Browser diese API überhaupt direkt ansprechen?
- Eine Drittanbieter-API, die einen geheimen Schlüssel braucht (OpenAI, Stripe-Secret-Key, die meisten E-Mail-Dienste), sollte niemals aus dem Browser aufgerufen werden. Der Schlüssel wäre für jeden Besucher sichtbar. Rufe sie stattdessen von deinem Backend auf, dann verschwindet das CORS-Problem, denn Server-zu-Server-Anfragen unterliegen nicht CORS. Siehe wie du API-Schlüssel sicher aufbewahrst.
- Eine Drittanbieter-API, die du nicht kontrollierst und die keine CORS-Header sendet, lässt sich von deiner Seite nicht beheben. Rufe sie von deinem Backend auf.
- Deine eigene API lässt sich beheben, indem du sie richtig konfigurierst. Weiter unten.
Schritt 3: Auf dem Server beheben
Der Server muss die richtigen Header zu seinen Antworten hinzufügen, einschließlich Fehlerantworten.
Für die eigentliche Anfrage sende:
Access-Control-Allow-Origin: https://myapp.com(der exakte Ursprung deines Frontends, ohne abschließenden Schrägstrich)Vary: Origin, wenn der Wert davon abhängt, welcher Ursprung angefragt hat
Für die OPTIONS-Preflight-Anfrage antworte mit einem Erfolgsstatus (200 oder 204) und:
Access-Control-Allow-Origin: https://myapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(jeder eigene Header, den du sendest)- Optional
Access-Control-Max-Age: 600, damit der Browser den Preflight eine Weile zwischenspeichert
Die meisten Frameworks haben ein Paket oder eine Einstellung dafür. In Express das Paket cors; in FastAPI CORSMiddleware; in ASP.NET Core AddCors; in Spring @CrossOrigin oder eine CORS-Konfiguration. Ein typisches Express-Setup:
import cors from "cors";
app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
credentials: true,
}));
Platziere die CORS-Behandlung vor deinen Routen und der Authentifizierung, damit Preflight-Anfragen (die keinen Login mitführen) nicht mit einem 401 abgelehnt werden.
Mit einem KI-Builder beschreibe das Setup präzise:
Das Frontend unter
https://myapp.comruft die API unterhttps://api.myapp.comauf und erhält „Response to preflight request doesn't pass access control check“. Konfiguriere CORS auf der API so, dass genauhttps://myapp.comund die Vorschau-Origin erlaubt sind, erlaube GET, POST, PATCH, DELETE mit den Headern Content-Type und Authorization, beantworte OPTIONS vor der Authentifizierung und füge CORS-Header auch zu Fehlerantworten hinzu.
Schritt 4: Cookies und Zugangsdaten behandeln
Wenn dein Frontend Cookies (etwa eine Login-Sitzung) an einen anderen Ursprung sendet, müssen beide Seiten übereinstimmen:
- Das Frontend setzt
credentials: "include"beifetchoderwithCredentials: truebei axios. - Der Server sendet
Access-Control-Allow-Credentials: true. - Das
Access-Control-Allow-Origindes Servers muss der exakte Ursprung sein, nicht*.
Cross-Site-Cookies brauchen außerdem SameSite=None; Secure am Cookie, und manche Browser schränken Drittanbieter-Cookies weiter ein. Das ist ein weiterer Grund, den Ansatz aus Schritt 5 zu bevorzugen.
Schritt 5: CORS mit einer Same-Origin-Konfiguration umgehen
Oft ist die sauberste Lösung, gar keine Cross-Origin-Anfragen zu stellen. Stelle die API unter demselben Ursprung wie die Seite bereit, zum Beispiel unter https://myapp.com/api/...:
- In der Entwicklung können die meisten Dev-Server proxyen. Vites
server.proxy-Einstellung kann/apian dein Backend auf einem anderen Port weiterleiten, sodass der Browser nur mit einem Ursprung spricht. - In der Produktion leitest du
/apiüber die Rewrite- oder Proxy-Einstellungen deines Hosts an das Backend weiter oder bedienst Frontend und API über einen einzigen Server.
Das Frontend ruft dann einen relativen Pfad auf, etwa fetch("/api/orders"). Es gibt keine Cross-Origin-Anfrage, keinen Cross-Origin-Preflight und keine Cookie-Probleme. Außerdem musst du keine API-Domain fest eintragen, die sich zwischen Vorschau und Produktion unterscheidet.
Stelle das Frontend so um, dass es das Backend über relative /api-Pfade statt über eine volle URL aufruft, und richte einen Entwicklungs-Proxy ein, der /api an den API-Server weiterleitet. Entferne danach alle CORS-Einstellungen, die wir nicht mehr brauchen.
Was du nicht tun solltest
mode: "no-cors"infetch. Es umgeht nichts; es liefert deinem Code eine leere, unlesbare Antwort.- Browser-Erweiterungen, die CORS deaktivieren. Sie ändern nur deinen Browser. Jeder Besucher sieht weiterhin den Fehler.
- Öffentliche „CORS-Proxy“-Dienste für echte Apps. Sie können alles lesen und verändern, was über sie läuft, und sie fallen aus.
Access-Control-Allow-Origin: *bei einer API mit Logins. Es funktioniert ohnehin nicht mit Zugangsdaten, und es ist der falsche Standard für private Daten.- Jeden
Origin-Header zurückspiegeln und dabei Zugangsdaten erlauben. Damit kann jede Website in deinem Namen angemeldete Anfragen für deine Nutzer stellen. Verwende eine Allowlist.
Häufige Ursachen in KI-gebauten Apps
| Situation | Lösung |
|---|---|
| Frontend ruft eine Drittanbieter-API mit einem geheimen Schlüssel auf | Den Aufruf ins Backend verschieben |
| Funktioniert in der Vorschau, schlägt auf der veröffentlichten Domain fehl | Die veröffentlichte Domain und die eigene Domain in die Allowlist aufnehmen oder relative /api-Pfade verwenden |
| Fehler nur bei POST, PUT oder DELETE | Preflight nicht behandelt; OPTIONS-Behandlung und erlaubte Header ergänzen |
| Fehler trat auf, nachdem ein Login hinzugefügt wurde | Zugangsdaten brauchen den exakten Ursprung und Allow-Credentials |
| „CORS-Fehler“, aber der Tab Netzwerk zeigt 500 | Zuerst den Serverfehler beheben |
API-URL ist fest auf localhost eingetragen | Relative Pfade oder eine Einstellung pro Umgebung verwenden |
CORS in Mythex
Wenn ein Mythex-Projekt eine Website und einen API-Server hat, laufen beide als Dienste im selben Projekt, und du kannst in der Vorschau zwischen ihnen wechseln. Wenn du den Agenten bittest, dass das Frontend das Backend über einen relativen /api-Pfad aufruft, der in der Entwicklung weitergeleitet wird, vermeidest du die meisten CORS-Probleme. Brauchst du wirklich Cross-Origin-Aufrufe, gib dem Agenten den genauen Fehler aus der Konsole und die beteiligten Ursprünge. Prüfe das Ergebnis auch in der veröffentlichten App, denn deren Adresse unterscheidet sich von der Vorschau. Siehe Multi-Service-Apps und API-Backends in der Dokumentation sowie unsere Leitfäden zum Debuggen einer KI-gebauten App und zu Frontend vs. Backend.
CORS-Checkliste
- Vollständigen Konsolenfehler und Statuscode der fehlgeschlagenen Anfrage gelesen
- Einen versteckten 404 oder 500 ausgeschlossen
- API mit geheimen Schlüsseln wird vom Backend aufgerufen, nicht vom Browser
- Server sendet
Access-Control-Allow-Originmit den exakten erlaubten Ursprüngen -
OPTIONS-Preflight beantwortet mit erlaubten Methoden und Headern, vor der Authentifizierung - CORS-Header auch bei Fehlerantworten vorhanden
- Zugangsdaten: exakter Ursprung,
Allow-Credentials: true, korrekte Cookie-Einstellungen - Vorschau-, veröffentlichte und eigene Domain-Ursprünge abgedeckt, oder relative
/api-Pfade verwendet - Keine
no-cors-, öffentlichen Proxy- oder Reflect-any-origin-Abkürzungen
Fragen
Was bedeutet ein CORS-Fehler?
Deine Seite, von einem Ursprung geladen, hat versucht, eine Antwort von einem anderen Ursprung zu lesen, und der Server dieser Antwort hat keine Header mitgeschickt, die das erlauben. Der Browser blockiert deinen Code, die Antwort zu lesen. Die Lösung liegt auf dem Server oder darin, wie die Anfrage geleitet wird, nicht im Frontend-Code.
Kann ich einen CORS-Fehler im Frontend beheben?
Nicht richtig. Einstellungen wie mode: 'no-cors' verbergen die Antwort nur vor deinem Code. Du behebst es, indem der Server den richtigen Access-Control-Allow-Origin-Header sendet oder die API über dein eigenes Backend bzw. einen Proxy auf derselben Origin aufrufst.
Ist Access-Control-Allow-Origin: * sicher?
Für öffentliche Daten, die jeder lesen darf, etwa eine öffentliche API ohne Login, ist es in Ordnung. Es lässt sich nicht mit Cookies oder anderen Zugangsdaten kombinieren, und bei privaten APIs solltest du die exakten erlaubten Origins auflisten.
Warum funktioniert meine Anfrage in Postman oder curl, aber nicht im Browser?
CORS wird nur von Browsern durchgesetzt. Tools wie Postman und curl wenden es nicht an, daher kann eine Anfrage dort erfolgreich sein und trotzdem blockiert werden, wenn das JavaScript der Seite sie stellt.
Was ist ein Preflight-Request?
Bei Anfragen, die nicht einfach sind, etwa ein JSON-POST oder eine Anfrage mit einem Authorization-Header, sendet der Browser zuerst eine OPTIONS-Anfrage und fragt den Server, welche Methoden und Header erlaubt sind. Schlägt diese OPTIONS-Anfrage fehl oder fehlen die richtigen Header, wird die eigentliche Anfrage nie gesendet.