Πώς να διορθώσετε σφάλματα CORS (και γιατί συμβαίνουν)
Ένα σφάλμα CORS σημαίνει ότι η ιστοσελίδα σας προσπάθησε να διαβάσει απάντηση από διαφορετική προέλευση (άλλο domain, θύρα ή πρωτόκολλο), και ο server δεν έστειλε κεφαλίδες που να λένε ότι επιτρέπεται. Ο browser μπλοκάρει την απάντηση για να προστατεύσει τον χρήστη. Το διορθώνετε στον server, επιστρέφοντας κεφαλίδα Access-Control-Allow-Origin για την προέλευση του site σας και χειριζόμενοι τα preflight αιτήματα OPTIONS, ή το αποφεύγετε στέλνοντας το αίτημα μέσω του δικού σας back end στην ίδια προέλευση.
Είναι από τα πιο μπερδεμένα σφάλματα στην ανάπτυξη ιστού, γιατί το αίτημα συχνά φτάνει κανονικά στον server. Αυτός ο οδηγός εξηγεί τι συμβαίνει και πώς να διορθώσετε κάθε παραλλαγή.
Τι σημαίνει «προέλευση»
Μια προέλευση είναι ο συνδυασμός πρωτοκόλλου, domain και θύρας:
| URL | Προέλευση |
|---|---|
https://myapp.com/dashboard | https://myapp.com |
https://api.myapp.com/users | https://api.myapp.com (διαφορετικός υποτομέας, άρα διαφορετική προέλευση) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (διαφορετική θύρα, άρα διαφορετική προέλευση) |
Οι browsers ακολουθούν την πολιτική ίδιας προέλευσης: η JavaScript μιας σελίδας μπορεί να διαβάζει ελεύθερα απαντήσεις από την ίδια προέλευση, αλλά όχι από άλλες. Το CORS (Cross-Origin Resource Sharing) είναι ο μηχανισμός με τον οποίο ο server δηλώνει τη συναίνεσή του: «οι σελίδες από αυτές τις προελεύσεις μπορούν να διαβάζουν τις απαντήσεις μου».
Δύο συνέπειες εκπλήσσουν τους περισσότερους:
- Το αίτημα συχνά φτάνει στον server. Το CORS συνήθως μπλοκάρει τον κώδικά σας από το να διαβάσει την απάντηση, όχι τον server από το να λάβει το αίτημα. Ένα POST μπορεί να έχει αποθηκευτεί παρότι είδατε σφάλμα.
- Το επιβάλλουν μόνο οι browsers. Τα curl, Postman και ο κώδικας στον server αγνοούν εντελώς το CORS. Γι' αυτό το «δουλεύει στο Postman» δεν λέει τίποτα για το CORS.
Βήμα 1: Διαβάστε το ακριβές σφάλμα
Ανοίξτε τα εργαλεία προγραμματιστή (δεξί κλικ → Επιθεώρηση), πηγαίνετε στην Κονσόλα και διαβάστε όλο το μήνυμα. Η διατύπωση του Chrome δείχνει ποιο πρόβλημα έχετε:
| Το μήνυμα περιέχει | Τι δεν πάει καλά |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Ο server δεν έστειλε καθόλου την κεφαλίδα, ή το αίτημα απέτυχε πριν φτάσει στον κώδικα CORS (για παράδειγμα 404 ή 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Ο server επιτρέπει διαφορετική προέλευση από τη δική σας |
Response to preflight request doesn't pass access control check | Το preflight OPTIONS απέτυχε |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Στέλνετε cookies, και ο server απάντησε με * |
Request header field authorization is not allowed | Ο server δεν έχει βάλει εκείνη την κεφαλίδα στο Access-Control-Allow-Headers |
Μετά ανοίξτε την καρτέλα Network, βρείτε το αίτημα που αποτυγχάνει (και τυχόν αίτημα OPTIONS πριν από αυτό), και δείτε τον κωδικό κατάστασης και τις κεφαλίδες απάντησης.
Ελέγξτε πρώτα τον κωδικό κατάστασης. Πολλά «σφάλματα CORS» είναι στην πραγματικότητα σφάλμα server μεταμφιεσμένο. Αν ο server καταρρεύσει ή δώσει 404, η απάντηση σφάλματος συχνά δεν έχει κεφαλίδες CORS, οπότε ο browser αναφέρει CORS αντί για το πραγματικό πρόβλημα. Διορθώστε το 500 ή το 404, και το σφάλμα CORS μπορεί να εξαφανιστεί.
Βήμα 2: Αποφασίστε αν πρέπει να καλείτε αυτό το API από τον browser καθόλου
Πριν προσθέσετε κεφαλίδες, ρωτήστε: πρέπει ο browser να καλεί αυτό το API απευθείας;
- Ένα API τρίτου με μυστικό κλειδί (OpenAI, το μυστικό κλειδί του Stripe, οι περισσότερες υπηρεσίες email) δεν πρέπει ποτέ να καλείται από τον browser. Το κλειδί θα ήταν ορατό σε κάθε επισκέπτη. Καλέστε το από το back end σας, και το πρόβλημα CORS εξαφανίζεται, επειδή τα αιτήματα από server σε server δεν υπόκεινται σε CORS. Δείτε πώς να κρατάτε ασφαλή τα κλειδιά API.
- Ένα API τρίτου που δεν ελέγχετε και που δεν στέλνει κεφαλίδες CORS δεν μπορεί να διορθωθεί από την πλευρά σας. Καλέστε το από το back end σας.
- Το δικό σας API μπορεί να διορθωθεί με σωστή ρύθμιση. Συνεχίστε παρακάτω.
Βήμα 3: Διορθώστε το στον server σας
Ο server πρέπει να προσθέτει τις σωστές κεφαλίδες στις απαντήσεις του, συμπεριλαμβανομένων των απαντήσεων σφάλματος.
Για το πραγματικό αίτημα, στείλτε:
Access-Control-Allow-Origin: https://myapp.com(η ακριβής προέλευση του front end σας, χωρίς κάθετο στο τέλος)Vary: Origin, αν η τιμή εξαρτάται από το ποια προέλευση ζήτησε
Για το preflight OPTIONS, απαντήστε με κωδικό επιτυχίας (200 ή 204) και:
Access-Control-Allow-Origin: https://myapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(κάθε προσαρμοσμένη κεφαλίδα που στέλνετε)- Προαιρετικά
Access-Control-Max-Age: 600, ώστε ο browser να κρατά το preflight για λίγο
Τα περισσότερα frameworks έχουν πακέτο ή ρύθμιση που το κάνει αυτό. Στο Express, το πακέτο cors· στο FastAPI, το CORSMiddleware· στο ASP.NET Core, το AddCors· στο Spring, το @CrossOrigin ή μια ρύθμιση CORS. Μια τυπική ρύθμιση στο Express:
import cors from "cors";
app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
credentials: true,
}));
Βάλτε τον χειρισμό CORS πριν από τις διαδρομές και την πιστοποίηση, ώστε τα preflight αιτήματα (που δεν έχουν σύνδεση) να μην απορρίπτονται με 401.
Με builder με AI, περιγράψτε τη ρύθμιση με ακρίβεια:
Το front end στο
https://myapp.comκαλεί το API στοhttps://api.myapp.comκαι παίρνει «Response to preflight request doesn't pass access control check». Ρύθμισε το CORS στο API ώστε να επιτρέπει ακριβώς τοhttps://myapp.comκαι την προέλευση της προεπισκόπησης, να επιτρέπει GET, POST, PATCH, DELETE με κεφαλίδες Content-Type και Authorization, να χειρίζεται το OPTIONS πριν από την πιστοποίηση, και να βάζει κεφαλίδες CORS και στις απαντήσεις σφάλματος.
Βήμα 4: Χειριστείτε cookies και credentials
Αν το front end στέλνει cookies (για παράδειγμα συνεδρία σύνδεσης) σε άλλη προέλευση, και οι δύο πλευρές πρέπει να συμφωνούν:
- Το front end ορίζει
credentials: "include"στοfetch, ήwithCredentials: trueστο axios. - Ο server στέλνει
Access-Control-Allow-Credentials: true. - Το
Access-Control-Allow-Originτου server πρέπει να είναι η ακριβής προέλευση, όχι*.
Τα cookies μεταξύ site χρειάζονται επίσης SameSite=None; Secure, και μερικοί browsers περιορίζουν περισσότερο τα cookies τρίτων. Ένας ακόμα λόγος να προτιμάτε την προσέγγιση του Βήματος 5.
Βήμα 5: Αποφύγετε το CORS με ρύθμιση ίδιας προέλευσης
Συχνά η καθαρότερη λύση είναι να μην κάνετε καθόλου αιτήματα μεταξύ προελεύσεων. Σερβίρετε το API από την ίδια προέλευση με τη σελίδα, για παράδειγμα στο https://myapp.com/api/...:
- Κατά την ανάπτυξη, οι περισσότεροι dev servers μπορούν να κάνουν proxy. Η ρύθμιση
server.proxyτου Vite μπορεί να προωθεί το/apiστο back end σας σε άλλη θύρα, ώστε ο browser να μιλά μόνο με μία προέλευση. - Στην παραγωγή, δρομολογήστε το
/apiστο back end μέσω των ρυθμίσεων rewrite ή proxy του host, ή σερβίρετε το front end και το API από έναν server.
Τότε το front end καλεί μια σχετική διαδρομή όπως fetch("/api/orders"). Δεν υπάρχει αίτημα μεταξύ προελεύσεων, ούτε preflight μεταξύ προελεύσεων, ούτε προβλήματα με cookies. Σημαίνει επίσης ότι δεν γράφετε σκληρά ένα domain API που διαφέρει ανάμεσα στην προεπισκόπηση και στην παραγωγή.
Άλλαξε το front end ώστε να καλεί το back end με σχετικές διαδρομές /api αντί για πλήρες URL, και ρύθμισε έναν proxy ανάπτυξης ώστε το /api να προωθείται στον server του API. Μετά αφαίρεσε τυχόν ρυθμίσεις CORS που δεν χρειάζονται πια.
Τι να μην κάνετε
mode: "no-cors"στοfetch. Δεν παρακάμπτει τίποτα· δίνει στον κώδικά σας μια κενή, μη αναγνώσιμη απάντηση.- Επεκτάσεις browser που απενεργοποιούν το CORS. Αλλάζουν μόνο τον δικό σας browser. Κάθε επισκέπτης βλέπει ακόμα το σφάλμα.
- Δημόσιες υπηρεσίες «CORS proxy» για πραγματικές εφαρμογές. Μπορούν να διαβάσουν και να αλλάξουν ό,τι περνά από αυτές, και καταρρέουν.
Access-Control-Allow-Origin: *σε API που χρησιμοποιεί συνδέσεις. Δεν λειτουργεί με credentials έτσι κι αλλιώς, και είναι λάθος προεπιλογή για ιδιωτικά δεδομένα.- Αντανάκλαση οποιασδήποτε κεφαλίδας
Originπίσω με επιτρεπόμενα credentials. Αυτό επιτρέπει σε οποιονδήποτε ιστότοπο να κάνει αιτήματα με σύνδεση εκ μέρους των χρηστών σας. Χρησιμοποιήστε λίστα επιτρεπόμενων.
Συνηθισμένες αιτίες σε εφαρμογές με AI
| Κατάσταση | Διόρθωση |
|---|---|
| Το front end καλεί API τρίτου με μυστικό κλειδί | Μεταφέρετε την κλήση στο back end |
| Δουλεύει στην προεπισκόπηση, αποτυγχάνει στο δημοσιευμένο domain | Προσθέστε τις προελεύσεις του δημοσιευμένου domain και του προσαρμοσμένου domain στη λίστα, ή χρησιμοποιήστε σχετικές διαδρομές /api |
| Σφάλμα μόνο σε POST, PUT ή DELETE | Το preflight δεν χειρίζεται· προσθέστε χειρισμό OPTIONS και επιτρεπόμενες κεφαλίδες |
| Το σφάλμα εμφανίστηκε μετά την προσθήκη σύνδεσης | Τα credentials θέλουν ακριβή προέλευση και Allow-Credentials |
| «Σφάλμα CORS» αλλά η καρτέλα Network δείχνει 500 | Διορθώστε πρώτα το σφάλμα του server |
Η διεύθυνση API είναι γραμμένη σκληρά ως localhost | Χρησιμοποιήστε σχετικές διαδρομές ή ρύθμιση ανά περιβάλλον |
CORS στο Mythex
Όταν ένα project του Mythex έχει ιστότοπο και server API, και τα δύο τρέχουν ως υπηρεσίες στο ίδιο project, και μπορείτε να εναλλάσσεστε μεταξύ τους στην προεπισκόπηση. Το να ζητήσετε από τον πράκτορα να κάνει το front end να καλεί το back end μέσω σχετικής διαδρομής /api, με proxy στην ανάπτυξη, αποφεύγει τα περισσότερα προβλήματα CORS. Αν χρειάζεστε πράγματι αιτήματα μεταξύ προελεύσεων, δώστε στον πράκτορα το ακριβές σφάλμα της κονσόλας και τις προελεύσεις που εμπλέκονται. Ελέγξτε το αποτέλεσμα και στη δημοσιευμένη εφαρμογή, γιατί η διεύθυνσή της διαφέρει από την προεπισκόπηση. Δείτε Υπηρεσίες πολλαπλών σημείων και Back end API στην τεκμηρίωση, και τους οδηγούς μας για αποσφαλμάτωση εφαρμογής φτιαγμένης με AI και front end έναντι back end.
Λίστα ελέγχου για CORS
- Διαβάστηκε το πλήρες σφάλμα της κονσόλας και ο κωδικός κατάστασης του αιτήματος που αποτυγχάνει
- Αποκλείστηκε ένα κρυφό 404 ή 500
- Τα API με μυστικά κλειδιά καλούνται από το back end, όχι από τον browser
- Ο server στέλνει
Access-Control-Allow-Originμε τις ακριβείς επιτρεπόμενες προελεύσεις - Το preflight
OPTIONSαπαντά με επιτρεπόμενες μεθόδους και κεφαλίδες, πριν από την πιστοποίηση - Οι κεφαλίδες CORS υπάρχουν και στις απαντήσεις σφάλματος
- Credentials: ακριβής προέλευση,
Allow-Credentials: true, σωστές ρυθμίσεις cookies - Καλύπτονται οι προελεύσεις προεπισκόπησης, δημοσιευμένου και προσαρμοσμένου domain, ή χρησιμοποιούνται σχετικές διαδρομές
/api - Χωρίς
no-cors, δημόσιους proxies ή συντομεύσεις αντανάκλασης κάθε προέλευσης
Ερωτήσεις
Τι σημαίνει σφάλμα CORS;
Η σελίδα σας, φορτωμένη από μία προέλευση, προσπάθησε να διαβάσει απάντηση από άλλη προέλευση, και ο server εκείνος δεν συμπεριέλαβε κεφαλίδες που το επιτρέπουν. Ο browser μπλοκάρει τον κώδικά σας από το να διαβάσει την απάντηση. Η διόρθωση γίνεται στον server, ή στον τρόπο δρομολόγησης του αιτήματος, όχι στον κώδικα του front end.
Μπορώ να διορθώσω σφάλμα CORS από το front end;
Όχι σωστά. Ρυθμίσεις όπως το mode: 'no-cors' απλώς κρύβουν την απάντηση από τον κώδικά σας. Τη διορθώνετε κάνοντας τον server να στέλνει σωστή κεφαλίδα Access-Control-Allow-Origin, ή καλώντας το API από το δικό σας back end ή έναν proxy ίδιας προέλευσης.
Είναι ασφαλές το Access-Control-Allow-Origin: *;
Είναι εντάξει για δημόσια δεδομένα που μπορεί να διαβάσει ο καθένας, όπως ένα δημόσιο API χωρίς σύνδεση. Δεν μπορεί να χρησιμοποιηθεί με cookies ή άλλα credentials, και για ιδιωτικά API πρέπει να καταγράφετε τις ακριβείς επιτρεπόμενες προελεύσεις.
Γιατί το αίτημα δουλεύει στο Postman ή στο curl αλλά όχι στον browser;
Το CORS επιβάλλεται μόνο από τους browsers. Εργαλεία όπως το Postman και το curl δεν το εφαρμόζουν, οπότε ένα αίτημα μπορεί να πετύχει εκεί και να μπλοκάρεται όταν το στέλνει η JavaScript της σελίδας.
Τι είναι το preflight αίτημα;
Για αιτήματα που δεν είναι απλά, όπως ένα POST JSON ή ένα αίτημα με κεφαλίδα Authorization, ο browser στέλνει πρώτα ένα αίτημα OPTIONS ρωτώντας τον server ποιες μεθόδους και κεφαλίδες επιτρέπονται. Αν το OPTIONS αποτύχει ή δεν έχει τις σωστές κεφαλίδες, το πραγματικό αίτημα δεν στέλνεται ποτέ.