Kako popraviti CORS greške (i zašto se javljaju)
CORS greška znači da je vaša web stranica pokušala da pročita odgovor s drugog izvora (drugog domena, porta ili protokola), a taj server nije poslao zaglavlja koja kažu da je to dozvoljeno. Pregledači blokiraju odgovor radi zaštite korisnika. Popravljate to na serveru, vraćanjem zaglavlja Access-Control-Allow-Origin za izvor vašeg sajta i obradom OPTIONS preflight zahtjeva, ili to izbjegavate slanjem zahtjeva kroz vlastiti backend na istom izvoru.
Riječ je o jednoj od najzbunjujućih grešaka u web razvoju, jer zahtjev često uspješno stiže do servera. Ovaj vodič objašnjava šta se dešava i kako popraviti svaku varijantu.
Šta znači „izvor”
Izvor je kombinacija protokola, domena i porta:
| URL | Izvor |
|---|---|
https://myapp.com/dashboard | https://myapp.com |
https://api.myapp.com/users | https://api.myapp.com (drugi poddomen, pa drugi izvor) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (drugi port, pa drugi izvor) |
Pregledači slijede politiku istog izvora: JavaScript na stranici može slobodno čitati odgovore sa svog izvora, ali ne i s drugih. CORS (Cross-Origin Resource Sharing) je sistem koji serveru omogućava da se uključi: „odgovore sa mene mogu čitati stranice s ovih izvora.”
Dvije posljedice iznenađuju ljude:
- Zahtjev često stigne do servera. CORS obično blokira vaš kod da pročita odgovor, a ne server da primi zahtjev. POST može biti sačuvan iako ste vidjeli grešku.
- Samo pregledači ga primjenjuju. curl, Postman i kod na serverskoj strani potpuno ignorišu CORS. Zato to što „radi u Postmanu” ne govori ništa o CORS-u.
Korak 1: Pročitajte tačnu grešku
Otvorite alate za developere (desni klik → Inspect), idite na Console i pročitajte cijelu poruku. Chromeova formulacija pokazuje koji problem imate:
| Poruka sadrži | Šta nije u redu |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Server uopšte nije poslao zaglavlje ili je zahtjev pao prije nego što je stigao do vašeg CORS koda (na primjer 404 ili 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Server dozvoljava drugi izvor, a ne vaš |
Response to preflight request doesn't pass access control check | OPTIONS preflight nije prošao |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Šaljete kolačiće, a server je odgovorio sa * |
Request header field authorization is not allowed | Server nije naveo to zaglavlje u Access-Control-Allow-Headers |
Zatim otvorite karticu Network, pronađite neuspješni zahtjev (i eventualni OPTIONS zahtjev prije njega) i pogledajte njegov statusni kod i zaglavlja odgovora.
Prvo provjerite statusni kod. Mnoge „CORS greške” su zapravo greška servera u prerušenju. Ako server padne ili vrati 404, njegov odgovor o grešci često nema CORS zaglavlja, pa pregledač prijavljuje CORS umjesto pravog problema. Popravite 500 ili 404, i CORS greška može nestati.
Korak 2: Odlučite treba li uopšte zvati taj API iz pregledača
Prije dodavanja zaglavlja pitajte se: treba li pregledač direktno zvati ovaj API?
- API treće strane koji traži tajni ključ (OpenAI, Stripe tajni ključ, većina servisa za e-poštu) nikada ne smije biti pozivan iz pregledača. Ključ bi bio vidljiv svakom posjetiocu. Pozovite ga iz svog backenda, a CORS problem nestaje, jer se zahtjevi server-na-server ne podvrgavaju CORS-u. Pogledajte kako čuvati API ključeve.
- API treće strane koji ne kontrolišete i koji ne šalje CORS zaglavlja ne može se popraviti s vaše strane. Pozovite ga iz svog backenda.
- Vlastiti API može se popraviti pravilnom konfiguracijom. Nastavite ispod.
Korak 3: Popravite na svom serveru
Server mora dodati ispravna zaglavlja svojim odgovorima, uključujući odgovore o greškama.
Za stvarni zahtjev pošaljite:
Access-Control-Allow-Origin: https://myapp.com(tačan izvor vašeg front enda, bez završne kose crte)Vary: Origin, ako vrijednost zavisi od toga koji izvor je tražio
Za preflight OPTIONS zahtjev odgovorite statusom uspjeha (200 ili 204) i:
Access-Control-Allow-Origin: https://myapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(svako prilagođeno zaglavlje koje šaljete)- Opciono
Access-Control-Max-Age: 600, da pregledač keširati preflight neko vrijeme
Većina okvira ima paket ili postavku koja to radi. U Expressu je to paket cors; u FastAPI-ju CORSMiddleware; u ASP.NET Core-u AddCors; u Springu @CrossOrigin ili CORS konfiguracija. Tipična Express postavka:
import cors from "cors";
app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
credentials: true,
}));
Stavite CORS obradu prije svojih ruta i autentifikacije, da preflight zahtjevi (koji ne nose prijavu) ne budu odbijeni s 401.
S AI alatom opišite postavku precizno:
Front end na
https://myapp.compoziva API nahttps://api.myapp.comi dobija „Response to preflight request doesn't pass access control check”. Konfiguriši CORS na API-ju tako da dozvoljava tačnohttps://myapp.comi izvor preview-a, dozvoli GET, POST, PATCH, DELETE sa zaglavljima Content-Type i Authorization, obradi OPTIONS prije autentifikacije i uključi CORS zaglavlja i u odgovore o greškama.
Korak 4: Obradite kolačiće i kredencijale
Ako vaš front end šalje kolačiće (na primjer sesiju prijave) drugom izvoru, obje strane se moraju složiti:
- Front end postavlja
credentials: "include"nafetch, iliwithCredentials: trueu axiosu. - Server šalje
Access-Control-Allow-Credentials: true. Access-Control-Allow-Originna serveru mora biti tačan izvor, a ne*.
Kolačići između različitih sajtova također trebaju SameSite=None; Secure na kolačiću, a neki pregledači dodatno ograničavaju kolačiće trećih strana. To je još jedan razlog da se radije odlučite za pristup iz Koraka 5.
Korak 5: Izbjegnite CORS pomoću postavke istog izvora
Često je najčistije rješenje da uopšte ne pravite zahtjeve između različitih izvora. Servirajte API s istog izvora kao stranicu, na primjer na https://myapp.com/api/...:
- U razvoju, većina razvojnih servera može raditi kao proxy. Postavka
server.proxyu Vite-u može proslijediti/apivašem backendu na drugom portu, pa pregledač uvijek komunicira s jednim izvorom. - U produkciji, prosljeđujte
/apibackendu kroz postavke rewrite-a ili proxyja vašeg hosta, ili servirajte front end i API s jednog servera.
Front end tada poziva relativnu putanju poput fetch("/api/orders"). Nema zahtjeva između različitih izvora, nema preflighta između izvora i nema problema s kolačićima. Također znači da ne morate hard-kodirati domen API-ja koji se razlikuje između preview-a i produkcije.
Promijeni front end da poziva backend preko relativnih /api putanja umjesto punog URL-a i postavi dev proxy tako da /api ide na API server. Zatim ukloni CORS postavke koje više nisu potrebne.
Šta ne raditi
mode: "no-cors"ufetch-u. Ništa ne zaobilazi; vašem kodu daje prazan, nečitljiv odgovor.- Dodaci za pregledač koji isključuju CORS. Mijenjaju samo vaš pregledač. Svaki posjetilac i dalje vidi grešku.
- Javni „CORS proxy” servisi za prave aplikacije. Mogu čitati i mijenjati sve što prolazi kroz njih, a i sami znaju da padnu.
Access-Control-Allow-Origin: *na API-ju koji koristi prijave. Ionako ne radi s kredencijalima i pogrešan je podrazumijevani izbor za privatne podatke.- Vraćanje bilo kojeg
Originzaglavlja nazad uz dozvoljene kredencijale. To omogućava bilo kojem sajtu da šalje zahtjeve u ime vaših prijavljenih korisnika. Koristite listu dozvoljenih.
Česti uzroci u aplikacijama napravljenim uz AI
| Situacija | Rješenje |
|---|---|
| Front end poziva API treće strane s tajnim ključem | Premjestite poziv na backend |
| Radi u preview-u, ne radi na objavljenom domenu | Dodajte objavljeni izvor i izvor prilagođenog domena na listu dozvoljenih ili koristite relativne /api putanje |
| Greška samo na POST, PUT ili DELETE | Preflight nije obrađen; dodajte obradu OPTIONS i dozvoljena zaglavlja |
| Greška se pojavila nakon dodavanja prijave | Kredencijalima treba tačan izvor i Allow-Credentials |
| „CORS greška”, ali karticu Network pokazuje 500 | Prvo popravite grešku servera |
URL API-ja hard-kodiran na localhost | Koristite relativne putanje ili postavku po okruženju |
CORS u Mythexu
Kada Mythex projekat ima web sajt i API server, oba rade kao servisi u istom projektu i možete prelaziti s jednog na drugi u preview-u. Ako zamolite agenta da front end poziva backend kroz relativnu /api putanju, proksirano u razvoju, izbjegavate većinu CORS problema. Ako ipak trebate pozive između različitih izvora, dajte agentu tačnu grešku iz konzole i uključene izvore. Provjerite rezultat i na objavljenoj aplikaciji, jer se njena adresa razlikuje od preview-a. Pogledajte Aplikacije s više servisa i API backendi u dokumentaciji, kao i naše vodiče o otklanjanju grešaka u aplikaciji napravljenoj uz AI i frontend naspram backenda.
Kontrolna lista za CORS
- Pročitana cijela greška iz konzole i statusni kod neuspjelog zahtjeva
- Isključen skriveni 404 ili 500
- API-ji s tajnim ključevima pozivaju se s backenda, a ne iz pregledača
- Server šalje
Access-Control-Allow-Origins tačnim dozvoljenim izvorima -
OPTIONSpreflight odgovoren dozvoljenim metodama i zaglavljima, prije autentifikacije - CORS zaglavlja prisutna i u odgovorima o greškama
- Kredencijali: tačan izvor,
Allow-Credentials: true, ispravne postavke kolačića - Pokriveni izvori preview-a, objavljene aplikacije i prilagođenog domena, ili korištene relativne
/apiputanje - Nema
no-cors, javnih proxyja ili prečica koje vraćaju bilo koji izvor
Pitanja
Šta znači CORS greška?
Vaša stranica, učitana iz jednog izvora, pokušala je da pročita odgovor s drugog izvora, a odgovor tog servera nije sadržao zaglavlja koja to dozvoljavaju. Pregledač blokira vaš kod da pročita odgovor. Rješenje je na serveru ili u tome kako se zahtjev rutira, a ne u frontend kodu.
Mogu li popraviti CORS grešku s frontenda?
Ne na pravi način. Postavke poput mode: 'no-cors' samo sakrivaju odgovor od vašeg koda. Popravljate tako što server šalje ispravno zaglavlje Access-Control-Allow-Origin ili tako što API poziva iz vašeg backenda ili preko proxyja istog izvora.
Da li je Access-Control-Allow-Origin: * sigurno?
U redu je za javne podatke koje svako može čitati, poput javnog API-ja bez prijave. Ne može se koristiti s kolačićima ni drugim kredencijalima, a za privatne API-je treba navesti tačne dozvoljene izvore.
Zašto moj zahtjev radi u Postmanu ili curlu, ali ne u pregledaču?
CORS primjenjuju samo pregledači. Alati poput Postmana i curla ga ne primjenjuju, pa zahtjev tamo može uspjeti, a da bude blokiran kada ga pokrene JavaScript stranice.
Šta je preflight zahtjev?
Za zahtjeve koji nisu jednostavni, poput JSON POST zahtjeva ili zahtjeva sa zaglavljem Authorization, pregledač prvo šalje OPTIONS zahtjev i pita server koje metode i zaglavlja su dozvoljena. Ako taj OPTIONS zahtjev padne ili nema ispravna zaglavlja, pravi zahtjev se nikada ne šalje.