Cum repari erorile CORS (și de ce apar)
O eroare CORS înseamnă că pagina ta web a încercat să citească un răspuns de la o altă origine (alt domeniu, port sau protocol), iar acel server nu a trimis header-e care să spună că este permis. Browserele blochează răspunsul ca să protejeze utilizatorii. O repari pe server, returnând un header Access-Control-Allow-Origin pentru originea site-ului tău și tratând cererile preflight OPTIONS, sau o eviți trimițând cererea prin propriul backend, pe aceeași origine.
Este una dintre cele mai confuze erori din dezvoltarea web, pentru că adesea cererea ajunge la server fără probleme. Acest ghid explică ce se întâmplă și cum se repară fiecare variantă.
Ce înseamnă „origine”
O origine este combinația dintre protocol, domeniu și port:
| URL | Origine |
|---|---|
https://aplicatia-mea.ro/dashboard | https://aplicatia-mea.ro |
https://api.aplicatia-mea.ro/users | https://api.aplicatia-mea.ro (alt subdomeniu, deci altă origine) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (alt port, deci altă origine) |
Browserele urmează same-origin policy: JavaScript-ul unei pagini poate citi liber răspunsurile de la propria origine, dar nu de la altele. CORS (Cross-Origin Resource Sharing) este sistemul prin care un server își dă acordul: „răspunsurile mele pot fi citite de pagini din aceste origini.”
Două consecințe surprind pe mulți:
- Cererea ajunge adesea la server. CORS de obicei blochează codul tău să citească răspunsul, nu serverul să primească cererea. Un POST poate fi salvat chiar dacă ai văzut o eroare.
- Doar browserele aplică regula. curl, Postman și codul de pe server ignoră complet CORS. De aceea „funcționează în Postman” nu spune nimic despre CORS.
Pasul 1: Citește eroarea exactă
Deschide uneltele de dezvoltator (click dreapta → Inspect), mergi la tab-ul Console și citește mesajul complet. Formularea Chrome îți spune ce problemă ai:
| Mesajul conține | Ce nu este în regulă |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Serverul nu a trimis deloc header-ul sau cererea a eșuat înainte să ajungă la codul tău CORS (de exemplu un 404 sau un 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Serverul permite o altă origine decât a ta |
Response to preflight request doesn't pass access control check | Preflight-ul OPTIONS a eșuat |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Trimiți cookie-uri, iar serverul a răspuns cu * |
Request header field authorization is not allowed | Serverul nu a listat header-ul respectiv în Access-Control-Allow-Headers |
Apoi deschide tab-ul Network, găsește cererea care a eșuat (și orice cerere OPTIONS dinaintea ei) și uită-te la codul de status și la header-ele de răspuns.
Verifică întâi codul de status. Multe „erori CORS” sunt de fapt o eroare de server în deghizare. Dacă serverul se blochează sau returnează 404, răspunsul de eroare nu are adesea header-ele CORS, deci browserul raportează CORS în loc de problema reală. Repară eroarea 500 sau 404, și eroarea CORS poate dispărea.
Pasul 2: Decide dacă ar trebui să apelezi API-ul acela din browser
Înainte să adaugi header-e, întreabă-te: ar trebui ca browserul să apeleze direct acest API?
- Un API terț care cere o cheie secretă (OpenAI, cheia secretă Stripe, majoritatea serviciilor de e-mail) nu ar trebui apelat niciodată din browser. Cheia ar fi vizibilă pentru fiecare vizitator. Apelează-o din backend-ul tău, iar problema CORS dispare, pentru că cererile server-la-server nu sunt supuse CORS. Vezi cum păstrezi în siguranță cheile API.
- Un API terț pe care nu îl controlezi, care nu trimite header-e CORS, nu poate fi reparat din partea ta. Apelează-o din backend-ul tău.
- API-ul tău poate fi reparat configurându-l corect. Continuă mai jos.
Pasul 3: Repară pe serverul tău
Serverul trebuie să adauge header-ele corecte la răspunsurile sale, inclusiv la răspunsurile de eroare.
Pentru cererea efectivă, trimite:
Access-Control-Allow-Origin: https://aplicatia-mea.ro(originea exactă a frontend-ului tău, fără slash la final)Vary: Origin, dacă valoarea depinde de originea care a cerut
Pentru cererea preflight OPTIONS, răspunde cu un status de succes (200 sau 204) și cu:
Access-Control-Allow-Origin: https://aplicatia-mea.roAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(fiecare header personalizat pe care îl trimiți)- Opțional
Access-Control-Max-Age: 600, ca browserul să păstreze în cache preflight-ul un timp
Majoritatea framework-urilor au un pachet sau o setare care face asta. În Express, pachetul cors; în FastAPI, CORSMiddleware; în ASP.NET Core, AddCors; în Spring, @CrossOrigin sau o configurare CORS. Un exemplu tipic în Express:
import cors from "cors";
app.use(cors({
origin: ["https://aplicatia-mea.ro", "http://localhost:5173"],
credentials: true,
}));
Pune gestionarea CORS înainte de rutele și de autentificarea ta, ca cererile preflight (care nu transportă autentificare) să nu fie respinse cu 401.
Cu un constructor cu AI, descrie setarea precis:
Frontend-ul de la
https://aplicatia-mea.roapelează API-ul de lahttps://api.aplicatia-mea.roși primește „Response to preflight request doesn't pass access control check”. Configurează CORS pe API ca să permită exacthttps://aplicatia-mea.roși originea de previzualizare, permite GET, POST, PATCH, DELETE cu header-ele Content-Type și Authorization, tratează OPTIONS înainte de autentificare și include header-ele CORS și în răspunsurile de eroare.
Pasul 4: Tratează cookie-urile și credențialele
Dacă frontend-ul tău trimite cookie-uri (de exemplu o sesiune de autentificare) către o altă origine, ambele părți trebuie să fie de acord:
- Frontend-ul setează
credentials: "include"lafetchsauwithCredentials: trueîn axios. - Serverul trimite
Access-Control-Allow-Credentials: true. Access-Control-Allow-Originde pe server trebuie să fie originea exactă, nu*.
Cookie-urile între site-uri au nevoie și de SameSite=None; Secure, iar unele browsere restricționează suplimentar cookie-urile terț. Acesta este încă un motiv să preferi abordarea de la Pasul 5.
Pasul 5: Evită CORS printr-o configurare pe aceeași origine
Adesea cea mai curată soluție este să nu faci deloc cereri între origini. Servește API-ul de pe aceeași origine cu pagina, de exemplu la https://aplicatia-mea.ro/api/...:
- În dezvoltare, majoritatea serverelor de dezvoltare pot face proxy. Setarea
server.proxydin Vite poate trimite/apicătre backend-ul tău de pe alt port, astfel încât browserul să vorbească doar cu o singură origine. - În producție, trimite
/apicătre backend prin setările de rewrite sau proxy ale hostului tău, sau servește frontend-ul și API-ul de pe același server.
Frontend-ul apelează atunci o cale relativă, de exemplu fetch("/api/orders"). Nu există cerere între origini, nu există preflight între origini și nu există probleme cu cookie-urile. Înseamnă și că nu fixezi un domeniu de API hard-codat, care diferă între previzualizare și producție.
Schimbă frontend-ul ca să apeleze backend-ul prin căi relative /api în loc de un URL complet și configurează un proxy de dezvoltare, astfel încât /api să fie trimis către serverul API. Apoi elimină setările CORS care nu mai sunt necesare.
Ce să nu faci
mode: "no-cors"înfetch. Nu ocolește nimic; îi dă codului tău un răspuns gol și ilizibil.- Extensii de browser care dezactivează CORS. Schimbă doar browserul tău. Fiecare vizitator vede în continuare eroarea.
- Servicii publice de „proxy CORS” pentru aplicații reale. Pot citi și modifica tot ce trece prin ele și se pot defecta.
Access-Control-Allow-Origin: *pe un API care folosește autentificare. Nu funcționează oricum cu credențiale și este un default greșit pentru date private.- Reflectarea oricărui header
Origincu credențiale permise. Asta lasă orice site web să facă cereri autentificate în numele utilizatorilor tăi. Folosește o listă de permise.
Cauze frecvente în aplicațiile construite cu AI
| Situație | Soluție |
|---|---|
| Frontend-ul apelează un API terț cu o cheie secretă | Mută apelul în backend |
| Funcționează în previzualizare, nu merge pe domeniul publicat | Adaugă originile publicate și ale domeniului personalizat în listă sau folosește căi relative /api |
| Eroare doar la POST, PUT sau DELETE | Preflight-ul nu este tratat; adaugă gestionarea OPTIONS și header-ele permise |
| Eroarea a apărut după ce ai adăugat autentificarea | Credențialele cer o origine exactă și Allow-Credentials |
| „Eroare CORS”, dar tab-ul Network arată 500 | Repară întâi eroarea de server |
URL-ul API-ului este hard-codat la localhost | Folosește căi relative sau o setare per mediu |
CORS în Mythex
Când un proiect Mythex are un site web și un server API, ambele rulează ca servicii în același proiect, iar între ele poți comuta în previzualizare. Dacă îi ceri agentului ca frontend-ul să apeleze backend-ul printr-o cale relativă /api, proxy-uită în dezvoltare, eviți majoritatea problemelor CORS. Dacă ai nevoie totuși de apeluri între origini, dă agentului eroarea exactă din consolă și originile implicate. Verifică rezultatul și pe aplicația publicată, pentru că adresa ei este diferită de cea din previzualizare. Vezi Servicii multiple și Backend-uri API în documentație, precum și ghidurile noastre despre cum depanezi o aplicație construită cu AI și frontend vs backend.
Lista de verificare CORS
- Am citit eroarea completă din consolă și codul de status al cererii care a eșuat
- Am exclus un 404 sau un 500 ascuns
- API-urile cu cheie secretă sunt apelate din backend, nu din browser
- Serverul trimite
Access-Control-Allow-Origincu originile exacte permise - Preflight-ul
OPTIONSprimește răspuns cu metodele și header-ele permise, înainte de autentificare - Header-ele CORS sunt prezente și în răspunsurile de eroare
- Credențiale: origine exactă,
Allow-Credentials: true, setări corecte pentru cookie-uri - Originile de previzualizare, publicare și domeniu personalizat sunt acoperite sau s-au folosit căi relative
/api - Nu s-au folosit
no-cors, proxy-uri publice sau reflectarea oricărei origini
Întrebări
Ce înseamnă o eroare CORS?
Pagina ta, încărcată de la o origine, a încercat să citească un răspuns de la o altă origine, iar răspunsul serverului respectiv nu includea header-ele care permit asta. Browserul îi blochează codului tău citirea răspunsului. Soluția este pe server sau în modul în care este rutată cererea, nu în codul frontend-ului.
Pot repara o eroare CORS din frontend?
Nu cum trebuie. Setări precum mode: 'no-cors' doar ascund răspunsul de codul tău, care rămâne ilizibil. Repari făcând serverul să trimită header-ul corect Access-Control-Allow-Origin sau apelând API-ul din propriul backend ori dintr-un proxy pe aceeași origine.
Este Access-Control-Allow-Origin: * sigur?
Este în regulă pentru date publice pe care oricine le poate citi, de exemplu un API public fără autentificare. Nu poate fi folosit cu cookie-uri sau alte credențiale, iar pentru API-uri private ar trebui să listezi originile exacte permise.
De ce funcționează cererea în Postman sau curl, dar nu în browser?
CORS este aplicat doar de browsere. Unelte precum Postman și curl nu îl aplică, deci o cerere poate reuși acolo și totuși să fie blocată când JavaScript-ul paginii o face.
Ce este o cerere preflight?
Pentru cererile care nu sunt simple, cum ar fi un POST JSON sau o cerere cu header-ul Authorization, browserul trimite mai întâi o cerere OPTIONS ca să întrebe serverul ce metode și header-e sunt permise. Dacă cererea OPTIONS eșuează sau nu are header-ele potrivite, cererea reală nu se mai trimite niciodată.