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 sa 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 je na serveru, tako što vraćate zaglavlje Access-Control-Allow-Origin za izvor vašeg sajta i obrađujete OPTIONS preflight zahteve, ili je izbegavate tako što zahtev šaljete preko sopstvenog back end-a na istom izvoru.
To je jedna od najzbunjujućih grešaka u web razvoju, jer zahtev često stiže do servera bez problema. 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 poštuju politiku istog izvora: JavaScript na stranici može slobodno da čita odgovore sa sopstvenog izvora, ali ne i sa drugih. CORS (Cross-Origin Resource Sharing) je sistem kojim server daje saglasnost: „odgovore sa mene mogu da čitaju stranice sa ovih izvora.“
Dve stvari iznenade ljude:
- Zahtev često stiže do servera. CORS obično blokira vaš kod da pročita odgovor, a ne da server primi zahtev. POST je možda sačuvan iako ste videli grešku.
- Samo pregledači ga primenjuju. curl, Postman i kod na serveru ga potpuno ignorišu. Zato „radi u Postman-u“ ne govori ništa o CORS-u.
Korak 1: Pročitajte tačnu grešku
Otvorite alate za programere (desni klik → Inspect), idite na Console i pročitajte celu poruku. Chrome-ov tekst 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 zahtev pukao pre nego što je stigao do vašeg CORS koda (na primer 404 ili 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Server dozvoljava drugi izvor od vašeg |
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, nađite neuspeli zahtev (i sve OPTIONS zahteve pre njega), i pogledajte njegov statusni kod i zaglavlja odgovora.
Prvo proverite statusni kod. Mnoge „CORS greške“ su zapravo serverska greška u maski. Ako server pukne ili vrati 404, njegov odgovor o grešci često nema CORS zaglavlja, pa pregledač prijavljuje CORS umesto pravog problema. Popravite 500 ili 404, a CORS greška može da nestane.
Korak 2: Odlučite da li uopšte treba da zovete taj API iz pregledača
Pre nego što dodate zaglavlja, pitajte se: treba li pregledač uopšte da zove ovaj API direktno?
- API treće strane koji traži tajni ključ (OpenAI, Stripe tajni ključ, većina servisa za mejl) nikada ne treba zvati iz pregledača. Ključ bi bio vidljiv svakom posetiocu. Pozovite ga iz back end-a, a CORS problem nestaje, jer zahtevi između servera nisu predmet CORS-a. Pogledajte kako čuvati API ključeve bezbednim.
- API treće strane koji ne kontrolišete i koji ne šalje CORS zaglavlja ne može se popraviti sa vaše strane. Pozovite ga iz back end-a.
- Vaš API može da se popravi pravilnim podešavanjem. Nastavite dole.
Korak 3: Popravite na serveru
Server mora da dodaje ispravna zaglavlja svojim odgovorima, uključujući odgovore o greškama.
Za sam zahtev pošaljite:
Access-Control-Allow-Origin: https://myapp.com(tačan izvor vašeg frontenda, bez kose crte na kraju)Vary: Origin, ako vrednost zavisi od toga koji izvor je pitao
Za preflight OPTIONS zahtev odgovorite statusom uspeha (200 ili 204) i sa:
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, kako bi pregledač keširao preflight neko vreme
Većina framework-a ima paket ili podešavanje koje ovo radi. U Express-u je to paket cors; u FastAPI-ju CORSMiddleware; u ASP.NET Core-u AddCors; u Spring-u @CrossOrigin ili CORS konfiguracija. Tipično podešavanje u Express-u:
import cors from "cors";
app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
credentials: true,
}));
Stavite CORS obradu pre svojih ruta i autentifikacije, kako preflight zahtevi (koji nemaju prijavu) ne bi bili odbijeni sa 401.
Sa AI alatom za izradu, precizno opišite podešavanje:
Frontend na
https://myapp.compoziva API nahttps://api.myapp.comi dobija „Response to preflight request doesn't pass access control check“. Podesi CORS na API-ju da dozvoli tačnohttps://myapp.comi izvor preview-a, dozvoli GET, POST, PATCH, DELETE sa zaglavljima Content-Type i Authorization, obradi OPTIONS pre autentifikacije, i uključi CORS zaglavlja i u odgovore o greškama.
Korak 4: Rukujte kolačićima i kredencijalima
Ako frontend šalje kolačiće (na primer sesiju za prijavu) ka drugom izvoru, obe strane moraju da se slože:
- Frontend postavlja
credentials: "include"nafetch, iliwithCredentials: trueu axios-u. - Server šalje
Access-Control-Allow-Credentials: true. Access-Control-Allow-Originna serveru mora biti tačan izvor, a ne*.
Kolačići među sajtovima takođe zahtevaju 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 preferira pristup iz Koraka 5.
Korak 5: Izbegnite CORS podešavanjem istog izvora
Često je najčistija popravka da uopšte ne pravite zahteve između izvora. Servirajte API sa istog izvora kao stranica, na primer na https://myapp.com/api/...:
- U razvoju većina razvojnih servera može da radi kao proxy. Vite-ova podešavanja
server.proxymogu da prosleđuju/apina vaš back end na drugom portu, pa pregledač uvek razgovara sa samo jednim izvorom. - U produkciji rutirajte
/apina back end kroz rewrite ili proxy podešavanja vašeg hosta, ili servirajte frontend i API sa jednog servera.
Frontend tada poziva relativnu putanju poput fetch("/api/orders"). Nema zahteva između izvora, nema preflight-a između izvora i nema problema sa kolačićima. Takođe znači da ne morate da ugrađujete domen API-ja koji se razlikuje između preview-a i produkcije.
Promeni frontend da poziva back end preko relativnih /api putanja umesto punog URL-a, i postavi razvojni proxy tako da /api ide na API server. Zatim ukloni CORS podešavanja koja više nisu potrebna.
Šta ne raditi
mode: "no-cors"ufetch-u. Ne zaobilazi ništa; vašem kodu daje prazan, nečitljiv odgovor.- Ekstenzije pregledača koje isključuju CORS. Menjaju samo vaš pregledač. Svaki posetilac i dalje vidi grešku.
- Javni „CORS proxy“ servisi za prave aplikacije. Mogu da čitaju i menjaju sve što prolazi kroz njih, a i sami povremeno padaju.
Access-Control-Allow-Origin: *na API-ju koji koristi prijave. Ne radi sa kredencijalima, a loš je podrazumevani izbor za privatne podatke.- Vraćanje bilo kog
Originzaglavlja nazad uz dozvoljene kredencijale. Tako bilo koji sajt može da pravi zahteve u ime vaših korisnika koji su prijavljeni. Koristite listu dozvoljenih.
Česti uzroci u aplikacijama napravljenim uz AI
| Situacija | Popravka |
|---|---|
| Frontend poziva API treće strane sa tajnim ključem | Premestite poziv na back end |
| Radi u pregledu, ne radi na objavljenom domenu | Dodajte objavljeni i prilagođeni domen na listu dozvoljenih, ili koristite relativne /api putanje |
| Greška samo na POST, PUT ili DELETE | Preflight nije obrađen; dodajte OPTIONS obradu i dozvoljena zaglavlja |
| Greška se pojavila posle dodavanja prijave | Kredencijalima treba tačan izvor i Allow-Credentials |
| „CORS greška“, ali kartica Network pokazuje 500 | Prvo popravite serversku grešku |
URL API-ja tvrdo kodiran na localhost | Koristite relativne putanje ili podešavanje po okruženju |
CORS u Mythex-u
Kada Mythex projekat ima sajt i API server, oba rade kao servisi u istom projektu, a između njih možete da prelazite u pregledu. Ako zamolite agenta da frontend zove back end preko relativne /api putanje, proksirane u razvoju, izbegavate većinu CORS problema. Ako vam ipak trebaju pozivi između izvora, dajte agentu tačnu grešku iz konzole i uključene izvore. Proverite rezultat i na objavljenoj aplikaciji, jer se njena adresa razlikuje od preview-a. Pogledajte Višeservisne aplikacije i API backend-i u dokumentaciji, i naše vodiče o otklanjanju grešaka u aplikaciji napravljenoj uz AI i frontend naspram backend-a.
Kontrolna lista za CORS
- Pročitana cela greška u konzoli i statusni kod neuspelog zahteva
- Isključen skriveni 404 ili 500
- API-ji sa tajnim ključevima pozivaju se iz back end-a, a ne iz pregledača
- Server šalje
Access-Control-Allow-Originsa tačnim dozvoljenim izvorima -
OPTIONSpreflight odgovara dozvoljenim metodama i zaglavljima, pre autentifikacije - CORS zaglavlja su prisutna i u odgovorima o greškama
- Kredencijali: tačan izvor,
Allow-Credentials: true, ispravna podešavanja kolačića - Izvori preview-a, objavljenog i prilagođenog domena pokriveni, ili su korišćene relativne
/apiputanje - Nema
no-cors, javnih proxy-ja, ni prihvatanja bilo kog izvora
Pitanja
Šta znači CORS greška?
Vaša stranica, učitana sa jednog izvora, pokušala je da pročita odgovor sa drugog izvora, a odgovor tog servera nije sadržao zaglavlja koja to dozvoljavaju. Pregledač blokira vaš kod da pročita odgovor. Popravka je na serveru, ili u tome kako se zahtev rutira, a ne u frontend kodu.
Mogu li da popravim CORS grešku iz frontenda?
Ne na pravi način. Podešavanja 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 pozivate iz sopstvenog back end-a ili proxy-ja na istom izvoru.
Da li je Access-Control-Allow-Origin: * bezbedno?
Dobro je za javne podatke koje svako sme da čita, poput javnog API-ja bez prijave. Ne može se koristiti sa kolačićima ili drugim kredencijalima, a za privatne API-je treba navesti tačne dozvoljene izvore.
Zašto zahtev radi u Postman-u ili curl-u, a ne u pregledaču?
CORS primenjuju samo pregledači. Alati poput Postman-a i curl-a ga ne primenjuju, pa zahtev može da uspe tamo, a da bude blokiran kada ga pošalje JavaScript stranice.
Šta je preflight zahtev?
Za zahteve koji nisu jednostavni, poput JSON POST-a ili zahteva sa zaglavljem Authorization, pregledač prvo šalje OPTIONS zahtev i pita server koje metode i zaglavlja su dozvoljeni. Ako taj OPTIONS zahtev ne uspe ili nema ispravna zaglavlja, pravi zahtev se uopšte ne šalje.