Jak opravit chyby CORS (a proč vznikají)
Chyba CORS znamená, že se vaše webová stránka pokusila číst odpověď z jiného původu (jiné domény, portu nebo protokolu) a tento server neposlal hlavičky, že je to povoleno. Prohlížeče odpověď zablokují, aby chránily uživatele. Opravuje se na serveru: vrácením hlavičky Access-Control-Allow-Origin pro původ vašeho webu a zpracováním preflight požadavků OPTIONS. Nebo se jí vyhnete tak, že požadavek pošlete přes vlastní backend na stejném původu.
Je to jedna z nejmatoucích chyb ve vývoji webu, protože požadavek na server často dorazí v pořádku. Tento návod vysvětluje, co se děje, a jak opravit každou variantu.
Co znamená „původ“
Původ je kombinace protokolu, domény a portu:
| URL | Původ |
|---|---|
https://mojeapp.cz/dashboard | https://mojeapp.cz |
https://api.mojeapp.cz/users | https://api.mojeapp.cz (jiná subdoména, tedy jiný původ) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (jiný port, tedy jiný původ) |
Prohlížeče dodržují politiku stejného původu: JavaScript na stránce si volně přečte odpovědi ze svého vlastního původu, ale ne z cizích. CORS (Cross-Origin Resource Sharing) je systém, kterým se server může rozhodnout: „odpovědi ode mě smějí číst stránky z těchto původů.“
Dva důsledky lidi často překvapí:
- Požadavek často server dostane. CORS obvykle blokuje, aby váš kód četl odpověď, ne aby server přijal požadavek. POST může být uložen, i když jste viděli chybu.
- Vynucují ho jen prohlížeče. curl, Postman a kód na serveru CORS ignorují úplně. Proto „v Postmanu to funguje“ o CORS nic neříká.
Krok 1: Přečtěte přesnou chybu
Otevřete vývojářské nástroje (pravý klik → Prozkoumat), přejděte na Konzoli a přečtěte celou zprávu. Formulace Chrome ukazuje, jaký problém máte:
| Zpráva obsahuje | Co je špatně |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Server hlavičku vůbec neposlal, nebo požadavek selhal dřív, než dorazil k vašemu CORS kódu (například 404 nebo 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Server povoluje jiný původ, než je ten váš |
Response to preflight request doesn't pass access control check | Preflight OPTIONS selhal |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Posíláte cookies a server odpověděl * |
Request header field authorization is not allowed | Server nevypsal tuto hlavičku v Access-Control-Allow-Headers |
Pak otevřete záložku Síť, najděte selhavší požadavek (a případný předchozí požadavek OPTIONS) a podívejte se na jeho stavový kód a hlavičky odpovědi.
Nejdřív zkontrolujte stavový kód. Mnoho „chyb CORS“ je ve skutečnosti chyba serveru v přestrojení. Pokud server spadne nebo vrátí 404, jeho chybová odpověď často nemá CORS hlavičky, takže prohlížeč nahlásí CORS místo skutečného problému. Opravte 500 nebo 404 a chyba CORS může zmizet.
Krok 2: Rozhodněte, zda by to API vůbec měl volat prohlížeč
Než přidáte hlavičky, zeptejte se: má prohlížeč toto API volat přímo?
- API třetí strany, které vyžaduje tajný klíč (OpenAI, tajný klíč Stripe, většina e-mailových služeb), by se nikdy nemělo volat z prohlížeče. Klíč by viděl každý návštěvník. Volejte ho z backendu a problém s CORS zmizí, protože požadavky server-server nepodléhají CORS. Viz jak chránit API klíče.
- API třetí strany, které nespravujete, a které neposílá CORS hlavičky, nelze opravit z vaší strany. Volejte ho z backendu.
- Vaše vlastní API lze opravit správným nastavením. Pokračujte níže.
Krok 3: Opravte to na svém serveru
Server musí do odpovědí přidat správné hlavičky, včetně chybových odpovědí.
Pro samotný požadavek pošlete:
Access-Control-Allow-Origin: https://mojeapp.cz(přesný původ vašeho frontendu, bez koncového lomítka)Vary: Origin, pokud hodnota závisí na tom, který původ se ptá
Pro preflight požadavek OPTIONS odpovězte úspěšným stavem (200 nebo 204) a:
Access-Control-Allow-Origin: https://mojeapp.czAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(každou vlastní hlavičku, kterou posíláte)- Volitelně
Access-Control-Max-Age: 600, aby prohlížeč preflight chvíli cachoval
Většina frameworků má balíček nebo nastavení, které to dělá. V Express je to balíček cors; ve FastAPI CORSMiddleware; v ASP.NET Core AddCors; ve Springu @CrossOrigin nebo konfigurace CORS. Typické nastavení v Express:
import cors from "cors";
app.use(cors({
origin: ["https://mojeapp.cz", "http://localhost:5173"],
credentials: true,
}));
Zpracování CORS dejte před své trasy a autentizaci, aby preflight požadavky (které nemají přihlášení) nebyly odmítnuty s 401.
U nástroje s AI popište nastavení přesně:
Frontend na
https://mojeapp.czvolá API nahttps://api.mojeapp.cza dostává „Response to preflight request doesn't pass access control check“. Nastav CORS na API tak, aby povolilo přesněhttps://mojeapp.cza původ náhledu, povolilo GET, POST, PATCH, DELETE s hlavičkami Content-Type a Authorization, zpracovalo OPTIONS před autentizací a CORS hlavičky posílalo i u chybových odpovědí.
Krok 4: Zpracujte cookies a přihlašovací údaje
Pokud frontend posílá cookies (například relaci přihlášení) na jiný původ, musí se obě strany shodnout:
- Frontend nastaví
credentials: "include"ufetch, nebowithCredentials: trueu axios. - Server pošle
Access-Control-Allow-Credentials: true. Access-Control-Allow-Originna serveru musí být přesný původ, ne*.
Cookies napříč weby také potřebují SameSite=None; Secure, a některé prohlížeče omezují cookies třetích stran ještě dál. To je další důvod, proč dát přednost přístupu z kroku 5.
Krok 5: Vyhněte se CORS nastavením na stejném původu
Často je nejčistší oprava vůbec nedělat požadavky mezi původy. Servírujte API ze stejného původu jako stránka, například na https://mojeapp.cz/api/...:
- Při vývoji mohou většina vývojových serverů fungovat jako proxy. Nastavení
server.proxyve Vite může přeposílat/apina váš backend na jiném portu, takže prohlížeč komunikuje jen s jedním původem. - V produkci směrujte
/apina backend přes přepisy nebo proxy nastavení hostingu, nebo servírujte frontend a API z jednoho serveru.
Frontend pak volá relativní cestu jako fetch("/api/orders"). Není žádný požadavek mezi původy, žádný preflight mezi původy a žádné problémy s cookies. Také to znamená, že nemusíte napevno zadávat doménu API, která se liší mezi náhledem a produkcí.
Změň frontend tak, aby volal backend přes relativní cesty /api místo plné URL, a nastav vývojový proxy, aby /api přeposílalo na API server. Potom odstraň CORS nastavení, která už nepotřebujeme.
Čeho se vyvarovat
mode: "no-cors"vefetch. Nic neobchází; dá vašemu kódu prázdnou, nečitelnou odpověď.- Rozšíření prohlížeče, která vypínají CORS. Mění jen váš prohlížeč. Každý návštěvník pořád uvidí chybu.
- Veřejné „CORS proxy“ služby pro skutečné aplikace. Mohou číst a měnit vše, co jimi prochází, a často nefungují.
Access-Control-Allow-Origin: *u API, které používá přihlášení. Stejně nefunguje s přihlašovacími údaji a je to špatný výchozí stav pro soukromá data.- Odrážení libovolné hlavičky
Originzpět s povolenými přihlašovacími údaji. Umožní to jakémukoli webu dělat požadavky jménem přihlášených uživatelů. Používejte seznam povolených.
Časté příčiny v aplikacích postavených s AI
| Situace | Oprava |
|---|---|
| Frontend volá API třetí strany s tajným klíčem | Přesuňte volání na backend |
| Funguje v náhledu, selže na publikované doméně | Přidejte publikovaný původ a původ vlastní domény na seznam povolených, nebo použijte relativní cesty /api |
| Chyba jen u POST, PUT nebo DELETE | Preflight není zpracován; přidejte zpracování OPTIONS a povolené hlavičky |
| Chyba se objevila po přidání přihlášení | Přihlašovací údaje vyžadují přesný původ a Allow-Credentials |
| „Chyba CORS“, ale záložka Síť ukazuje 500 | Nejdřív opravte chybu serveru |
URL API napevno nastavená na localhost | Použijte relativní cesty nebo nastavení podle prostředí |
CORS v Mythex
Když má projekt v Mythex web a API server, oba běží jako služby ve stejném projektu a v náhledu mezi nimi můžete přepínat. Pokud agentovi zadáte, ať frontend volá backend přes relativní cestu /api, která se ve vývoji přeposílá, většina problémů s CORS zmizí. Pokud přesto potřebujete volání mezi původy, dejte agentovi přesnou chybu z konzole a zapojené původy. Výsledek zkontrolujte i na publikované aplikaci, protože její adresa se liší od náhledu. Viz Multi-service apps a API backends v dokumentaci a naše návody jak ladit aplikaci postavenou s AI a frontend vs. backend.
Kontrolní seznam CORS
- Přečtena celá chyba v konzoli a stavový kód selhavšího požadavku
- Vyloučena skrytá 404 nebo 500
- API s tajnými klíči volána z backendu, ne z prohlížeče
- Server posílá
Access-Control-Allow-Origins přesně povolenými původy - Preflight
OPTIONSzodpovězen povolenými metodami a hlavičkami, před autentizací - CORS hlavičky přítomny i u chybových odpovědí
- Přihlašovací údaje: přesný původ,
Allow-Credentials: true, správná nastavení cookies - Pokryty původy náhledu, publikované aplikace i vlastní domény, nebo použity relativní cesty
/api - Žádné
no-cors, veřejné proxy ani zkratky s odrážením libovolného původu
Otázky
Co znamená chyba CORS?
Vaše stránka, načtená z jednoho původu, se pokusila číst odpověď z jiného původu a odpověď toho serveru neobsahovala hlavičky, které to povolují. Prohlížeč vašemu kódu čtení odpovědi zablokuje. Oprava je na serveru nebo v tom, jak je požadavek směrován, ne ve frontendovém kódu.
Můžu chybu CORS opravit z frontendu?
Ne pořádně. Nastavení jako mode: 'no-cors' jen skryjí odpověď před vaším kódem. Opravíte to tak, že server pošle správnou hlavičku Access-Control-Allow-Origin, nebo tím, že API budete volat z vlastního backendu nebo proxy na stejném původu.
Je Access-Control-Allow-Origin: * bezpečné?
Je v pořádku pro veřejná data, která smí číst kdokoli, třeba veřejné API bez přihlášení. Nedá se použít s cookies ani jinými přihlašovacími údaji a u soukromých API byste měli vypsat přesné povolené původy.
Proč požadavek funguje v Postmanu nebo curl, ale ne v prohlížeči?
CORS vynucují jen prohlížeče. Nástroje jako Postman a curl ho neuplatňují, takže požadavek může tam uspět a přitom být zablokován, když ho volá JavaScript stránky.
Co je preflight požadavek?
U požadavků, které nejsou jednoduché, například JSON POST nebo požadavek s hlavičkou Authorization, prohlížeč nejdřív pošle požadavek OPTIONS a zeptá se serveru, jaké metody a hlavičky jsou povoleny. Pokud tento požadavek OPTIONS selže nebo nemá správné hlavičky, skutečný požadavek se vůbec neodešle.