CORS endlich einmal und fia olle Moi vastehn
CORS-Fehler tauchn in da Konsole zum schlimmstn Zeitpunkt auf, sogn fost nix Nützlichs dazu, wia ma's behebt, und wern "glöst", indem ma Access-Control-Allow-Origin: * von Stack Overflow einekopiert, ohne dass wer vasteht, wos do grod passiert is. Do is, wos wirklich obgeht, und warum da Browser des mit dir absichtlich mocht.
Es is koa Server-Problem - es is a Browser-Problem
Des Erste zum Verinnerlichn: CORS (Cross-Origin Resource Sharing) wird komplett vom Browser durchgesetzt, ned vom Server. Wennst an Endpoint mit curl aufrufst, der im Browser "an CORS-Fehler hot", funktioniert's problemlos - weil curl CORS gor ned durchsetzt. Da Server schickt die Antwort imma; da Browser entscheidet, ob er dein JavaScript sie lesn losst.
Des gibt's wegn da Same-Origin-Policy: Standardmäßig kann a Skript auf https://app.example.com ka Antworten von https://api.other.com lesn, a wenn's technisch den Request schickn kann. Ohne des kunnt jede Website, de du besuchst, still und heimlich authentifizierte Anfragen an deine Bank in deim Nama stöin, mit Cookies, de da Browser automatisch mitschickt. CORS is da Mechanismus, mit dem a Server bestimmte ondere Origins explizit zulassn kann, seine Antworten zum lesn.
Origins, ganz genau
Zwoa URLs hom nur dann die gleiche Origin, wenn Schema, Host und Port exakt übereinstimmen.
https://app.example.com:443/page1
https://app.example.com:443/page2 → same origin (path doesn't matter)
http://app.example.com → different origin (scheme differs)
https://api.example.com → different origin (host differs)
https://app.example.com:8080 → different origin (port differs)
localhost:3000, des mit localhost:4000 redt, is in da Entwicklung a Cross-Origin-Request, drum rennen lokale Dev-Setups dauernd in CORS, a wenn "des ois localhost is".
Einfache Requests vs. Preflight-Requests
Ned jeder Cross-Origin-Request löst des söbe Browser-Verholtn aus. A Request gilt nur dann ois "einfach" - und spart si den zusätzlichen Roundtrip -, wenn er ziemlich enge Bedingungen erfüllt: Methode is GET, HEAD oda POST; nur a kleine Liste an Headern is gsetzt (Accept, Accept-Language, Content-Language, Content-Type); und Content-Type is oans von application/x-www-form-urlencoded, multipart/form-data oda text/plain.
Olles andere - a PUT, a Custom-Header wia Authorization oda X-Api-Key, a JSON-Body mit Content-Type: application/json - löst an Preflight aus: Da Browser schickt zuerst an OPTIONS-Request und fragt um Erlaubnis, bevor er den echten schickt.
OPTIONS /api/orders HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type, authorization
Da Server muass auf den Preflight explizit antwortn:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Access-Control-Max-Age is für de Performance wichtig: Er sagt dem Browser, wie long in Sekunden er des Preflight-Ergebnis cachen darf, bevor er wieda fragt. Ohne ihn zoit jeder PUT auf a JSON-API zwoa Requests statt oan.
A minimaler Express-Server, der's richtig mocht
app.use((req, res, next) => {
const allowedOrigins = ['https://app.example.com', 'http://localhost:3000'];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Vary', 'Origin');
}
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Max-Age', '86400');
if (req.method === 'OPTIONS') {
return res.sendStatus(204);
}
next();
});
Da Vary: Origin-Header is wichtig, wenn de Antwort irgendwo gecacht wern kunnt (CDN, geteilter Proxy) - er sogt dem Cache, dass da Antwort-Body vom Origin-Header vom Request abhängt, und er drum ned a Antwort, de für oane Origin gmeint woar, an an Request von ana ondern ausliefern soi.
Credentials sand Opt-in, und zwoamoi
Wenn a Request Cookies oda an Authorization-Header für a Session schicken muass, de Cross-Origin lebt, miassn beide Seiten explizit zustimmen:
// Client
fetch('https://api.example.com/orders', {
credentials: 'include',
});
// Server response
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Zwoa Sochn brechen do dauernd: Access-Control-Allow-Origin: * is von da Spec bei Credentials ausdrücklich verboten - du muasst a konkrete Origin zruckschickn, ka Wildcard - und wennst Access-Control-Allow-Credentials: true am Server vagisst, wirft da Browser die Antwort stumm weg, a wenn da Request söba erfolgreich woar.
Warum * ned nur a fauler Abkürzer is
Access-Control-Allow-Origin: * sogt dem Browser "jede Website im Internet darf diese Antwort lesn". Für a wirklich öffentliche, unauthentifizierte API (Wetter-API, öffentliches CDN-Asset) is des in Ordnung. Für olles, wos nutzerspezifische oda authentifizierte Daten liefert, hebt's den gesamten Sinn von da Same-Origin-Policy auf - jede Seitn, de da Nutzer besucht, kunnt die Daten per Hintergrund-Fetch lesn, wenn irgendwie Credentials dranghängt wern. Drum blockiern Requests mit Credentials den Wildcard direkt auf Spec-Ebene, statt drauf zum vertrauen, dass Entwickler de zwoa ned kombinieren.
Fazit
CORS is ka Bug in deim Server und ka Hindernis, des da Browser willkürlich aufstöt - es is da Browser, der durchsetzt, dass Cross-Origin-Lesezugriffe a explizites Opt-in pro Origin vom glesenen Server brauchen. Einfache Requests kriagn an leichten Header-Check; olles mit Custom-Header, nicht-trivialer Methode oda JSON-Body kriagt zuerst an Preflight. Wennst erlaubte Origin, erlaubte Header und Credentials-Flag richtig hast, verschwinden de Fehler, weil da Browser nix mehr zum Beanstandn hot. Und jetzt hör auf, * einezukopiern, du Gfrast!