Sie veröffentlichen ein neues Frontend, öffnen die Konsole – und sehen einen roten CORS-Fehler: Die Anfrage wurde „durch die CORS-Richtlinie blockiert“. Ihre API funktioniert in Apidog oder curl, aber der Browser übergibt die Antwort nicht an Ihr JavaScript. Das Problem ist meist schnell lösbar, wenn Sie die richtige Schicht prüfen.
Die wichtigste CORS-Regel
CORS (Cross-Origin Resource Sharing) erlaubt Servern, die Same-Origin-Policy des Browsers gezielt zu lockern. JavaScript von https://app.example.com darf standardmäßig keine Antworten von https://api.example.com lesen, wenn sich Schema, Host oder Port unterscheiden. Details finden Sie in der MDN-CORS-Dokumentation; der zugrunde liegende Algorithmus ist in der Fetch-Spezifikation definiert.
Drei Punkte lösen die meisten Missverständnisse:
-
Der Browser erzwingt CORS. Nur Browser führen diese Prüfung durch. Server-zu-Server-Aufrufe,
curlund Desktop-API-Clients ignorieren sie. - Der Server konfiguriert CORS. Der Browser entscheidet anhand der Response-Header des Servers. Ohne passende Header gibt es keinen Zugriff.
- Die Anfrage kann den Server trotzdem erreichen. Bei einfachen Anfragen verarbeitet der Server die Anfrage und antwortet; der Browser verbietet Ihrem JavaScript anschließend nur das Lesen der Antwort. CORS ist keine API-Firewall, sondern schützt Benutzer vor bösartigen Websites, die ursprungsübergreifend auf deren Cookies und Daten zugreifen.
Beheben Sie CORS daher normalerweise in der Serverkonfiguration – nicht mit einem Frontend-Workaround.
Preflight-Anfragen verstehen
Bei bestimmten Cross-Origin-Anfragen sendet der Browser zunächst eine OPTIONS-Anfrage, den sogenannten Preflight. Das geschieht beispielsweise bei:
- Methoden außer
GET,HEADoderPOST - benutzerdefinierten Headern wie
Authorization Content-Type: application/json
Beispiel:
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 Server sollte mit einem erfolgreichen Status und den benötigten Berechtigungen antworten:
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 Header oder ist der Status nicht erfolgreich, bricht der Browser die eigentliche Anfrage ab. Der Endpunkt wird dann nicht aufgerufen; in den Logs erscheint nur der OPTIONS-Treffer. Access-Control-Max-Age erlaubt dem Browser, die Entscheidung 86400 Sekunden zu cachen.
Beim Debugging hilft deshalb zuerst diese Frage:
Ist der Preflight fehlgeschlagen – oder die eigentliche Anfrage?
Die sechs häufigsten CORS-Fehler
1. Access-Control-Allow-Origin fehlt
Der Server sendet keine CORS-Header. Der Browser kann die Antwort deshalb nicht freigeben.
Für eine bestimmte Anwendung:
Access-Control-Allow-Origin: https://app.example.com
Für öffentliche, nicht authentifizierte APIs ist auch * möglich.
Achten Sie darauf, CORS-Header auch an Fehlerantworten anzuhängen. Wenn beispielsweise eine 500-Antwort keine Header enthält, sehen Sie im Browser einen CORS-Fehler statt des eigentlichen Serverfehlers. Das gilt ebenso für 403 Forbidden-Antworten; siehe auch die Erklärung zum Statuscode 403.
2. * wird mit Anmeldeinformationen verwendet
Diese Kombination ist ungültig:
Access-Control-Allow-Origin: *
wenn das Frontend credentials: 'include' verwendet oder Cookies beziehungsweise Authentifizierungsdaten sendet. Eine Wildcard würde jeder Website erlauben, authentifizierte Antworten zu lesen.
Verwenden Sie stattdessen einen konkreten Ursprung:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Validieren Sie den eingehenden Origin immer gegen eine Zulassungsliste. Geben Sie niemals beliebige Ursprünge zusammen mit aktivierten Anmeldeinformationen zurück.
3. Der Preflight besteht die Zugriffskontrolle nicht
Häufige Ursachen:
- Die Route unterstützt nur
POST, aber keinOPTIONS. - Der Server antwortet mit
404,405oder401. - Eine Authentifizierungs-Middleware lehnt den Preflight ab, obwohl Browser Preflights ohne Anmeldeinformationen senden.
Behandeln Sie OPTIONS vor der Authentifizierung und geben Sie einen 2xx-Status mit vollständigen CORS-Headern zurück:
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);
});
In vielen Frameworks reicht es, die CORS-Middleware früh in der Middleware-Kette einzubinden.
4. Der Origin-Wert stimmt nicht
Der Server sendet zwar Access-Control-Allow-Origin, aber für den falschen Ursprung. Typische Fehler:
- Produktion ist fest codiert, während Sie von
http://localhost:5173testen. -
httpundhttpswerden verwechselt. - Ein abschließender Schrägstrich wird verwendet:
https://app.example.com/ist kein gültiger Origin-Wert.
Vergleichen Sie den Origin exakt und senden Sie Vary: Origin:
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');
}
Vary: Origin verhindert, dass Caches oder CDNs die Antwort eines Ursprungs an einen anderen ausliefern.
5. Header oder Methode ist nicht erlaubt
Beispiele:
-
Authorizationfehlt inAccess-Control-Allow-Headers. -
PUTfehlt inAccess-Control-Allow-Methods.
Erweitern Sie die Preflight-Antwort um alle Methoden und Header, die Ihr Frontend tatsächlich sendet:
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-Request-Id
Header-Namen sind dabei unabhängig von Groß- und Kleinschreibung. HTTP-Methoden müssen in Großbuchstaben angegeben werden.
6. Eine Weiterleitung blockiert den Preflight
Browser folgen Weiterleitungen während eines Preflights nicht zuverlässig. Häufige Ursachen:
- Eine
http-URL wird zuhttpsumgeleitet. - Ein fehlender abschließender Schrägstrich löst eine Weiterleitung aus.
- Ein Gateway leitet
/v1/ordersauf/v1/orders/um.
Verwenden Sie im Frontend direkt die endgültige HTTPS-URL, halten Sie die Slash-Konvention Ihres Routers ein und prüfen Sie den Endpunkt mit einer manuellen OPTIONS-Anfrage. Die Antwort sollte 2xx statt 3xx liefern.
CORS-Konfiguration für gängige Stacks
Express
Verwenden Sie die offizielle cors-Middleware, statt Header manuell zu setzen:
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 die Middleware vor der Authentifizierung ein, damit Preflights nicht wegen fehlender Tokens abgelehnt werden.
Für Flask bietet die Flask-CORS-Erweiterung ein vergleichbares Muster.
Spring Boot
Eine globale Konfiguration mit 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, aktivieren Sie CORS zusätzlich in der Security-Filterkette:
.cors(Customizer.withDefaults())
Andernfalls kann die Sicherheitsebene Preflights blockieren, bevor die MVC-Konfiguration sie erreicht. Weitere Optionen finden Sie in der Spring-CORS-Dokumentation.
Nginx
Wenn Nginx die Anfrage vor Ihrer Anwendung terminiert, können Sie Preflights am Edge beantworten:
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-Parameter ist entscheidend: Ohne ihn entfernt Nginx add_header-Direktiven bei 4xx- und 5xx-Antworten. Außerdem sollte nur eine Schicht für CORS zuständig sein. Wenn sowohl Nginx als auch die Anwendung Header hinzufügen, können ungültige Duplikate wie Access-Control-Allow-Origin: *, * entstehen.
CORS außerhalb des Browsers mit Apidog debuggen
Der Konsolenfehler zeigt, dass der Browser etwas blockiert hat, aber nicht, welche Header der Server tatsächlich gesendet hat. Mit Apidog entfernen Sie den Browser aus der Fehleranalyse. Als Desktop-API-Client unterliegt Apidog keinen Browser-CORS-Prüfungen.
Gehen Sie so vor:
-
Eigentliche Anfrage wiederholen: Kopieren Sie Methode, Header und Body aus dem Netzwerk-Tab in Apidog. Ein
500-Status dort bedeutet, dass kein CORS-Problem vorliegt. -
Preflight manuell senden: Erstellen Sie eine
OPTIONS-Anfrage mit:
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type
-
Response-Header prüfen: Kontrollieren Sie
Access-Control-Allow-Origin,Access-Control-Allow-MethodsundAccess-Control-Allow-Headers. Achten Sie außerdem auf3xx-Statuscodes. -
Korrektur verifizieren: Senden Sie dieselbe gespeicherte
OPTIONS-Anfrage nach der Serveränderung erneut und vergleichen Sie die Header.
Dieser Ablauf trennt schnell einen echten API-Fehler von einer fehlerhaften CORS-Konfiguration. Desktop-Clients funktionieren, weil sie CORS umgehen; der Browser scheitert, weil die Serverantwort nicht die erforderlichen Header enthält. Weitere API-Testtechniken helfen bei der anschließenden Fehleranalyse.
30-Sekunden-CORS-Checkliste
Prüfen Sie vor der Fehlersuche:
- Enthält die fehlerhafte Antwort
Access-Control-Allow-Origin? - Stimmen Schema, Host und Port exakt mit dem Seiten-Origin überein?
- Gibt es keinen abschließenden Schrägstrich im Origin-Wert?
- Verwenden Sie Cookies oder Authentifizierung? Dann benötigen Sie einen konkreten Origin und
Access-Control-Allow-Credentials: true, niemals*. - Antwortet
OPTIONSmit2xx? - Decken die erlaubten Methoden und Header die tatsächliche Anfrage ab?
- Gibt es eine Weiterleitung auf der Preflight-URL?
- Enthalten
401-,403- und500-Antworten ebenfalls die CORS-Header?
In den meisten Fällen liegt die Ursache in einer dieser Prüfungen. Testen Sie die Korrektur mit einer manuellen OPTIONS-Anfrage in Apidog und passen Sie anschließend die Serverkonfiguration an.
FAQ
Warum erhalte ich nur im Browser einen CORS-Fehler?
Nur Browser setzen CORS durch. Die Same-Origin-Policy schützt Benutzer davor, dass bösartige Seiten authentifizierte Daten lesen. curl, Backend-Dienste und Desktop-Clients haben diese Einschränkung nicht. Wenn eine Anfrage außerhalb des Browsers funktioniert, fehlen auf dem Server wahrscheinlich CORS-Header oder sie sind falsch konfiguriert.
Gilt CORS für Postman oder Apidog?
Nein. Postman und Apidog sind Desktop-Anwendungen und laufen nicht in einer Browser-Sandbox. Sie umgehen CORS vollständig und zeigen die rohen Response-Header des Servers. Eine erfolgreiche Anfrage in einem Desktop-Client beweist daher nicht, dass die Anfrage im Browser funktioniert, hilft aber beim Eingrenzen der fehlerhaften Schicht. Weitere Informationen bietet der Postman-CORS-Testleitfaden.
Ist ein CORS-Fehler eine Sicherheitsfunktion oder ein Bug?
Eine Sicherheitsfunktion. Der Browser schützt die Antwortdaten, bis der Server den Cross-Origin-Zugriff ausdrücklich erlaubt. Das Deaktivieren von CORS über Browser-Flags oder Erweiterungen beseitigt nur das lokale Symptom; andere Benutzer erhalten weiterhin den Fehler. Korrigieren Sie die Server-Header.
Kann ich Access-Control-Allow-Origin: * überall verwenden?
Nur bei öffentlichen, schreibgeschützten APIs ohne Cookies oder Authentifizierung. Sobald Anmeldeinformationen beteiligt sind, wird die Wildcard abgelehnt. Für authentifizierte APIs verwenden Sie eine Origin-Zulassungsliste, geben den passenden Origin zurück und senden Vary: Origin, damit gemeinsam genutzte Caches die Antworten getrennt behandeln.
Top comments (0)