Sie veröffentlichen ein neues Frontend, öffnen die Konsole, und da ist er: ein roter CORS-Fehler, der Ihnen sagt, dass die Anfrage „durch die CORS-Richtlinie blockiert wurde“. Ihre API funktioniert einwandfrei in Apidog oder curl, doch der Browser weigert sich, Ihrem JavaScript die Antwort zu übergeben. Frustrierend? Ja. Mysteriös? Nicht, wenn Sie wissen, wo der Fehler liegt.
Hier ist die Kerninformation, die die meisten Tutorials verschweigen: Ein CORS-Fehler wird vom Browser erzwungen, aber vom Server verursacht. Der Browser blockiert die Antwort, weil Ihr Server nicht die richtigen Access-Control-Allow-Origin-Header gesendet hat. Die Lösung liegt also fast immer in der Serverkonfiguration, nicht in Ihrem Frontend-Code.
Dieser Leitfaden erklärt, was CORS bewirkt, wie die Preflight-Anfrage funktioniert, die sechs häufigsten CORS-Fehlermeldungen mit der genauen Lösung für jede einzelne sowie funktionierende Konfigurationen für Express, Spring Boot und Nginx. Sie erfahren auch, wie Sie außerhalb des Browsers debuggen können, was der schnellste Weg ist, um „Server falsch konfiguriert“ von „Browser blockiert“ zu unterscheiden.
Was ein CORS-Fehler ist (und was nicht)
CORS steht für Cross-Origin Resource Sharing (Ressourcenfreigabe über verschiedene Ursprünge). Standardmäßig setzen Browser die Same-Origin-Policy (Gleiche-Ursprungs-Richtlinie) durch: JavaScript, das auf https://app.example.com läuft, kann keine Antworten von https://api.example.com lesen, da Schema, Host oder Port abweichen. CORS ist der Mechanismus, den Server verwenden, um diese Regel absichtlich zu lockern. Die vollständigen Details finden Sie in der MDN CORS-Dokumentation, und der zugrunde liegende Algorithmus ist in der Fetch-Spezifikation definiert.
Drei Punkte klären die meisten Missverständnisse auf:
- Der Browser erzwingt es. Nur Browser wenden CORS-Prüfungen an. Server-zu-Server-Aufrufe, curl und Desktop-API-Clients ignorieren sie vollständig.
- Der Server konfiguriert es. Der Browser entscheidet auf Basis der Antwort-Header, die Ihr Server sendet. Keine Header, kein Zugriff.
- Die Anfrage erreicht den Server normalerweise trotzdem. Bei einfachen Anfragen verarbeitet der Server alles und antwortet. Der Browser verweigert dann Ihrem JavaScript die Antwort. CORS ist keine Sicherheitsmauer um Ihre API; es schützt Benutzer vor bösartigen Seiten, die ursprungsübergreifende Daten mit deren Cookies lesen.
Wenn Sie also einen CORS-Fehler sehen, greifen Sie nicht zu einem Frontend-Workaround. Lesen Sie die Fehlermeldung und beheben Sie dann den fehlenden oder falschen Header auf dem Server.
Anatomie der Preflight-Anfrage
Vor bestimmten Cross-Origin-Anfragen sendet der Browser einen „Scout“: eine OPTIONS-Anfrage, die als Preflight bezeichnet wird. Sie wird ausgelöst, wenn Ihre Anfrage Methoden über GET, HEAD oder POST hinaus verwendet, benutzerdefinierte Header wie Authorization sendet oder einen Content-Type wie application/json verwendet.
Die Preflight-Anfrage sieht so aus:
OPTIONS /v1/orders HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type
Der Browser fragt: „Eine Seite auf app.example.com möchte hier mit diesen Headern einen POST-Request senden. Erlaubt?“ Eine korrekte Serverantwort:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
Vary: Origin
Fehlt ein Element, bricht der Browser die eigentliche Anfrage ab, bevor sie überhaupt ausgeführt wird. Ihr API-Endpunkt wird nie aufgerufen, Ihre Logs zeigen nichts außer einem OPTIONS-Treffer, und die Konsole zeigt einen CORS-Fehler an. Access-Control-Max-Age weist den Browser an, dieses Urteil zu cachen (hier 86400 Sekunden), sodass wiederholte Anfragen den Preflight überspringen.
Behalten Sie diesen zweistufigen Tanz im Hinterkopf. Die Hälfte aller CORS-Debugging-Fälle lässt sich auf eine Frage reduzieren: Ist der Preflight fehlgeschlagen, oder ist die eigentliche Anfrage fehlgeschlagen?
Die 6 häufigsten CORS-Fehler und wie man sie behebt
Browser schreiben überraschend präzise CORS-Fehlermeldungen. Vergleichen Sie Ihre mit der folgenden Liste.
1. Der Header „Access-Control-Allow-Origin“ ist nicht vorhanden
Der Klassiker. Ihr Server hat eine Antwort ohne jegliche CORS-Header gesendet. Der Browser hatte nichts zu bewerten und blockierte daher den Zugriff.
Lösung: Konfigurieren Sie den Server so, dass er Access-Control-Allow-Origin entweder mit dem spezifischen anfragenden Ursprung oder mit * für öffentliche, anmeldefreie APIs sendet:
Access-Control-Allow-Origin: https://app.example.com
Eine Falle: Fehlerantworten überspringen oft CORS-Header, auch wenn Erfolgsantworten diese enthalten. Wenn Ihre API einen 500er-Fehler zurückgibt und die Middleware nur 200er-Antworten dekoriert, zeigt die Konsole einen CORS-Fehler anstelle des tatsächlichen Serverfehlers. Stellen Sie sicher, dass CORS-Header an jede Antwort angehängt werden, einschließlich 403 Forbidden und 500er-Seiten.
2. Wildcard „*“ kann nicht mit Anmeldeinformationen verwendet werden
Die Meldung lautet: „Der Wert des Headers ‚Access-Control-Allow-Origin‘ darf nicht der Wildcard-Wert ‚*‘ sein, wenn der Anmeldeinformationsmodus der Anfrage ‚include‘ ist.“
Ihr Frontend sendet Cookies oder Authentifizierungs-Header mit credentials: 'include', aber der Server antwortet mit Access-Control-Allow-Origin: *. Die Fetch-Spezifikation verbietet diese Kombination; eine Wildcard plus Anmeldeinformationen würde es jeder Website im Internet ermöglichen, authentifizierte Antworten zu lesen.
Lösung: Geben Sie den genauen Ursprung anstelle der Wildcard zurück und fügen Sie den Credentials-Header hinzu:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Validieren Sie den eingehenden Origin anhand einer Zulassungsliste, bevor Sie ihn zurückgeben. Das Zurückgeben beliebiger Ursprünge mit aktivierten Anmeldeinformationen untergräbt den gesamten Schutz.
3. Die Antwort auf die Preflight-Anfrage besteht die Zugriffskontrollprüfung nicht
Ihr Server hat die OPTIONS-Anfrage nie bearbeitet. Vielleicht definiert die Route nur POST, sodass OPTIONS einen 404 oder 405 zurückgibt. Vielleicht hat eine Auth-Middleware die Anfrage mit einem 401 abgelehnt, weil der Preflight kein Token enthält (Browser fügen Preflights niemals Anmeldeinformationen hinzu).
Lösung: Behandeln Sie OPTIONS explizit und geben Sie einen 2xx-Status mit dem vollständigen Satz von CORS-Headern zurück, bevor die Authentifizierung ausgeführt wird. In den meisten Frameworks löst die frühzeitige Einbindung der CORS-Middleware das Problem. Wenn Sie es manuell schreiben:
app.options('/v1/orders', (req, res) => {
res.set({
'Access-Control-Allow-Origin': 'https://app.example.com',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Authorization, Content-Type'
});
res.sendStatus(204);
});
4. Der Header-Wert stimmt nicht mit dem angegebenen Ursprung überein
Der Server sendet einen Access-Control-Allow-Origin-Header, aber er nennt den falschen Ursprung. Häufige Ursachen: ein fest codierter Produktionsursprung, während Sie von http://localhost:5173 testen, ein Fehler beim Vergleich der Zulassungsliste zwischen http und https oder ein versehentlicher abschließender Schrägstrich (https://app.example.com/ ist kein gültiger Ursprungswert).
Lösung: Vergleichen Sie den Origin-Header der Anfrage genau mit Ihrer Zulassungsliste, geben Sie die Übereinstimmung zurück und senden Sie Vary: Origin, damit Caches und CDNs den Header eines Ursprungs nicht einem anderen Ursprung servieren:
const allowed = ['https://app.example.com', 'http://localhost:5173'];
if (allowed.includes(req.headers.origin)) {
res.set('Access-Control-Allow-Origin', req.headers.origin);
res.set('Vary', 'Origin');
}
5. Anfrage-Header-Feld oder Methode ist nicht erlaubt
Zwei verwandte Meldungen: „Anfrage-Header-Feld Authorization ist nicht durch Access-Control-Allow-Headers in der Preflight-Antwort erlaubt“ und „Methode PUT ist nicht durch Access-Control-Allow-Methods erlaubt.“
Der Preflight war erfolgreich, aber seine Antwort deckte nicht ab, was Ihre Anfrage benötigt. Sie haben einen Authorization-Header oder einen X-Request-Id hinzugefügt, und die Zulassungsliste des Servers hat ihn nie erwähnt.
Lösung: Erweitern Sie die Preflight-Antwort, um jeden Header und jede Methode einzuschließen, die Ihr Frontend sendet:
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-Request-Id
Header-Namen sind hier Groß- und Kleinschreibung ignorierend. Methoden sind Groß- und Kleinschreibung beachtend und in Großbuchstaben.
6. Weiterleitung ist für eine Preflight-Anfrage nicht erlaubt
Der Preflight traf auf eine URL, die einen 301- oder 302-Status zurückgab, und Browser weigern sich, Weiterleitungen während des Preflights zu folgen. Typische Übeltäter: eine http-URL, die zu https weiterleitet, ein fehlender abschließender Schrägstrich, den Ihr Framework „hilfreich“ umleitet, oder ein Gateway, das /v1/orders auf /v1/orders/ umleitet.
Lösung: Richten Sie Ihr Frontend direkt auf die endgültige URL aus. Verwenden Sie von Anfang an https, passen Sie die Konvention für den abschließenden Schrägstrich Ihres Routers an und bestätigen Sie mit einem manuellen OPTIONS-Aufruf, ob der Endpunkt mit einem 2xx- anstelle eines 3xx-Status antwortet.
Beispiele für Serverkonfigurationen
Hier ist die korrekte CORS-Einrichtung in drei gängigen Stacks.
Express
Verwenden Sie die offizielle cors-Middleware, anstatt die Header manuell zu erstellen:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: ['https://app.example.com', 'http://localhost:5173'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Authorization', 'Content-Type'],
credentials: true,
maxAge: 86400
}));
Binden Sie sie vor Ihrer Auth-Middleware ein, damit Preflights niemals wegen fehlender Tokens abgelehnt werden. Python-Entwickler erhalten das gleiche Muster von der Flask-CORS-Erweiterung, die eine identische Header-Logik für Flask-Anwendungen kapselt.
Spring Boot
Globale Konfiguration über WebMvcConfigurer:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/v1/**")
.allowedOrigins("https://app.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Authorization", "Content-Type")
.allowCredentials(true)
.maxAge(86400);
}
}
Verwenden Sie Spring Security? Rufen Sie .cors(Customizer.withDefaults()) auch in Ihrer Security-Filterkette auf, da sonst die Sicherheitsebene Preflights blockiert, bevor die MVC-Konfiguration sie überhaupt sieht. Die vollständige Optionspalette finden Sie in der Spring CORS-Dokumentation.
Nginx
Wenn Nginx Anfragen vor Ihrer Anwendung terminiert, beantworten Sie Preflights am Edge:
location /v1/ {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Access-Control-Max-Age 86400 always;
return 204;
}
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Vary "Origin" always;
proxy_pass http://backend;
}
Der always-Flag ist wichtig. Ohne ihn verwirft Nginx add_header-Direktiven bei 4xx- und 5xx-Antworten, was bei jeder fehlgeschlagenen Anfrage Fehler Nummer eins wieder herstellt. Und wählen Sie eine Ebene, die für CORS zuständig ist: Wenn sowohl Nginx als auch Ihre Anwendung Header hinzufügen, sehen Browser Duplikate wie Access-Control-Allow-Origin: *, * und lehnen die Antwort ab.
CORS außerhalb des Browsers mit Apidog debuggen
Der Konsolenfehler zeigt Ihnen an, dass der Browser etwas blockiert hat. Er sagt Ihnen nicht, was der Server gesendet hat. Der schnellste Weg, die Wahrheit herauszufinden, ist, den Browser aus der Schleife zu nehmen.
Apidog ist ein Desktop-API-Client, daher unterliegen seine Anfragen überhaupt keinen Browser-CORS-Checks. Das ermöglicht ein sauberes Experiment: Senden Sie dieselbe Anfrage von Apidog, die Ihr Frontend gestellt hat. Wenn sie dort erfolgreich ist, ist Ihre API-Logik in Ordnung und das Problem sind lediglich fehlende CORS-Header. Wenn sie dort auch fehlschlägt, haben Sie einen gewöhnlichen API-Fehler im CORS-Gewand, und allgemeine API-Testtechniken sind anwendbar.
Eine CORS-Debugging-Sitzung in Apidog sieht so aus:
- Die tatsächliche Anfrage wiederholen. Kopieren Sie die fehlgeschlagene Anfrage aus dem Netzwerk-Tab Ihres Browsers und erstellen Sie sie in Apidog mit derselben Methode, denselben Headern und demselben Body neu. Überprüfen Sie Status und Body. Ein 500er hier bedeutet, dass CORS nie Ihr Problem war.
- Den Preflight manuell testen. Erstellen Sie eine neue Anfrage, setzen Sie die Methode auf
OPTIONSund fügen Sie die Header hinzu, die ein Browser senden würde:Origin: https://app.example.com,Access-Control-Request-Method: POSTundAccess-Control-Request-Headers: authorization, content-type. Senden Sie sie. - Die Antwort-Header inspizieren. Suchen Sie im Antwortbereich nach
Access-Control-Allow-Origin,Access-Control-Allow-MethodsundAccess-Control-Allow-Headers. Vergleichen Sie jeden Wert mit dem, was Ihr Frontend benötigt. Ein fehlender Header, ein falscher Ursprung oder ein 3xx-Status sticht sofort ins Auge, ohne Konsolen-Rätselraten. - Die Korrektur überprüfen. Nach dem Ändern der Serverkonfiguration senden Sie dieselbe gespeicherte
OPTIONS-Anfrage erneut und beobachten Sie, wie sich die Header aktualisieren. Kein erneutes Bereitstellen von Frontends, keine Cache-Löschrituale.
Dieser Workflow löst auch das ewige Argument „funktioniert in meinem API-Client, schlägt im Browser fehl“ in Sekunden, dasselbe Rätsel hinter der Postman CORS-Test-Frage. Der Client funktioniert, weil er CORS umgeht. Der Browser schlägt fehl, weil Ihr Server die magischen Worte nicht gesagt hat. Laden Sie Apidog kostenlos herunter und speichern Sie die OPTIONS-Anfrage neben Ihren regulären Endpunkt-Tests; zukünftige CORS-Brände werden mit einem Klick gelöscht.
Eine 30-Sekunden-CORS-Checkliste
Bevor Sie den Fehler melden, gehen Sie diese Liste durch:
- Enthält die fehlerhafte Antwort überhaupt
Access-Control-Allow-Origin? - Stimmt ihr Wert genau mit dem Ursprung Ihrer Seite überein (Schema, Host, Port, kein abschließender Schrägstrich)?
- Verwenden Sie Cookies oder Auth? Bestätigen Sie einen spezifischen Ursprung plus
Access-Control-Allow-Credentials: true, niemals*. - Gibt
OPTIONSeinen 2xx-Status mit Methoden und Headern zurück, die Ihre Anfrage abdecken? - Gibt es eine Weiterleitung auf der Preflight-URL?
- Enthalten Fehlerantworten (401, 403, 500) dieselben CORS-Header wie Erfolgsantworten?
In neun von zehn Fällen ist eine dieser sechs Zeilen Ihre Antwort. Überprüfen Sie dies mit einer manuellen OPTIONS-Anfrage in Apidog, patchen Sie die Serverkonfiguration und widmen Sie sich wieder dem Aufbau.
FAQ
Warum erhalte ich nur im Browser einen CORS-Fehler?
Weil nur Browser CORS durchsetzen. Die Same-Origin-Policy schützt Benutzer vor bösartigen Seiten, die ihre authentifizierten Daten lesen, daher überprüfen Browser Access-Control-Allow-Origin bei jeder Cross-Origin-Antwort. curl, Backend-Dienste und Desktop-Clients haben keine solche Regel. Wenn eine Anfrage überall außer im Browser erfolgreich ist, fehlen Ihrem Server CORS-Header oder sind falsch konfiguriert; die API selbst ist in Ordnung.
Gilt CORS für Postman oder Apidog?
Nein. Postman und Apidog sind Desktop-Anwendungen, keine Webseiten, die in einer Browser-Sandbox laufen, daher umgehen ihre Anfragen CORS vollständig. Genau das macht sie für das CORS-Debugging nützlich: Sie zeigen Ihnen die rohen Antwort-Header des Servers ohne die Filterung des Browsers. Die Verwirrung um den Postman CORS-Test beginnt meist hier; eine erfolgreiche Anfrage in einem Desktop-Client beweist nichts über das Browserverhalten, aber sie isoliert die fehlerhafte Schicht.
Ist ein CORS-Fehler eine Sicherheitsfunktion oder ein Bug?
Eine Funktion. CORS-Fehler bedeuten, dass der Browser seine Aufgabe erfüllt: Er weigert sich, ursprungsübergreifende Antwortdaten Skripten preiszugeben, es sei denn, der Server stimmt dem zu. Das Deaktivieren von CORS im Browser mit Flags oder Erweiterungen verbirgt das Symptom auf Ihrem Computer, während jeder Benutzer weiterhin auf die Barriere stößt. Beheben Sie stattdessen die Server-Header.
Kann ich Access-Control-Allow-Origin: * überall verwenden?
Nur für öffentliche, schreibgeschützte APIs ohne Cookies oder Authentifizierung. Die Wildcard wird abgelehnt, sobald Anmeldeinformationen enthalten sind, und sie kündigt an, dass Ihre Daten für jeden Ursprung im Web offen sind. Für alles Authentifizierte pflegen Sie eine Ursprungs-Zulassungsliste, geben Sie den passenden Ursprung zurück und senden Sie Vary: Origin, damit gemeinsame Caches die Antworten getrennt halten.
