როგორ გავასწოროთ CORS შეცდომები (და რატომ ხდება ისინი)
CORS შეცდომა ნიშნავს, რომ თქვენმა ვებგვერდმა სხვა წყაროდან (სხვა დომენიდან, პორტიდან ან პროტოკოლიდან) პასუხის წაკითხვა სცადა, და ის სერვერი არ გზავნიდა სათაურებს, რომლებიც ამის უფლებას იძლევა. ბრაუზერი პასუხს იმ მიზეზით ბლოკავს, რომ მომხმარებელი დაიცვას. გასწორება ხდება სერვერზე: დააბრუნეთ Access-Control-Allow-Origin სათაური თქვენი საიტის წყაროსთვის და დაამუშავეთ OPTIONS preflight მოთხოვნები, ან ავირიდოთ პრობლემა მოთხოვნის თქვენი backend-ის გავლით, იმავე წყაროზე.
ეს ერთ-ერთი ყველაზე დამაბნეველი შეცდომაა ვებ დეველოპმენტში, რადგან მოთხოვნა ხშირად სერვერამდე ნორმალურად აღწევს. ეს სახელმძღვანელო განმარტავს, რა ხდება და როგორ გავასწოროთ თითოეული ვარიანტი.
რას ნიშნავს „წყარო"
წყარო (origin) არის პროტოკოლის, დომენისა და პორტის კომბინაცია:
| 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 (სხვა პორტი, ამიტომ სხვა წყარო) |
ბრაუზერები იცავენ same-origin policy-ს: გვერდის JavaScript თავისუფლად კითხულობს პასუხებს საკუთარი წყაროდან, მაგრამ სხვისგან — არა. CORS (Cross-Origin Resource Sharing) არის სისტემა, რომლითაც სერვერი თანხმობას აცხადებს: „ჩემი პასუხების წაკითხვა შეუძლიათ გვერდებს ამ წყაროებიდან".
ორი რამ ხალხს ხშირად უკვირს:
- მოთხოვნა ხშირად სერვერამდე აღწევს. CORS ჩვეულებრივ თქვენს კოდს უკრძალავს პასუხის კითხვას, და არა სერვერს მოთხოვნის მიღებას. POST შეიძლება შენახული იყოს, მაშინაც კი, როცა შეცდომა დაინახეთ.
- მხოლოდ ბრაუზერები ახორციელებენ. curl, Postman და სერვერის მხარის კოდი CORS-ს სრულად უგულებელყოფს. ამიტომ „Postman-ში მუშაობს" CORS-ის შესახებ არაფერს ამბობს.
ნაბიჯი 1: წაიკითხეთ ზუსტი შეცდომა
გახსენით დეველოპერის ხელსაწყოები (მარჯვენა ღილაკი → Inspect), გადადით Console-ზე და წაიკითხეთ სრული შეტყობინება. Chrome-ის ფორმულირება გეტყვით, რა პრობლემა გაქვთ:
| შეტყობინება შეიცავს | რა არის არასწორი |
|---|---|
No 'Access-Control-Allow-Origin' header is present | სერვერმა სათაური საერთოდ არ გამოაგზავნა, ან მოთხოვნა CORS კოდამდე ჩაიშალა (მაგალითად 404 ან 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | სერვერი სხვა წყაროს უშვებს, ვიდრე თქვენი |
Response to preflight request doesn't pass access control check | OPTIONS preflight ჩაიშალა |
...must not be the wildcard '*' when the request's credentials mode is 'include' | თქვენ cookie-ებს აგზავნით, და სერვერმა * უპასუხა |
Request header field authorization is not allowed | სერვერმა ეს სათაური Access-Control-Allow-Headers-ში არ ჩამოთვალა |
შემდეგ გახსენით Network ჩანართი, იპოვეთ ჩაშლილი მოთხოვნა (და მის წინ არსებული OPTIONS მოთხოვნა), და შეხედეთ მის სტატუს კოდს და პასუხის სათაურებს.
ჯერ სტატუს კოდი შეამოწმეთ. ბევრი „CORS შეცდომა" სინამდვილეში სერვერის შეცდომაა, შენიღბული. თუ სერვერი ავარიულდა ან 404 დააბრუნა, მისი შეცდომის პასუხს ხშირად CORS სათაურები არ აქვს, ამიტომ ბრაუზერი რეალური პრობლემის ნაცვლად CORS-ს აცხადებს. გაასწორეთ 500 ან 404, და CORS შეცდომა შეიძლება გაქრეს.
ნაბიჯი 2: გადაწყვიტეთ, უნდა დარეკავდეს თუ არა ბრაუზერი ამ API-ს საერთოდ
სათაურების დამატებამდე იკითხეთ: უნდა ეძახდეს თუ არა ბრაუზერი ამ API-ს პირდაპირ?
- მესამე მხარის API, რომელსაც საიდუმლო გასაღები სჭირდება (OpenAI, Stripe-ის საიდუმლო გასაღები, უმეტესობა ელფოსტის სერვისებისა) არასდროს უნდა გამოიძახოთ ბრაუზერიდან. გასაღები ყველა ვიზიტორს დაენახებოდა. დარეკეთ თქვენი backend-იდან, და CORS პრობლემა გაქრება, რადგან სერვერ-სერვერის მოთხოვნებზე CORS არ მოქმედებს. იხილეთ როგორ შევინახოთ API გასაღებები უსაფრთხოდ.
- მესამე მხარის API, რომელსაც არ აკონტროლებთ და CORS სათაურებს არ აგზავნის, თქვენი მხრიდან ვერ გამოსწორდება. დარეკეთ თქვენი backend-იდან.
- თქვენი საკუთარი API შეიძლება სწორად კონფიგურირდეს. გააგრძელეთ ქვემოთ.
ნაბიჯი 3: გაასწორეთ სერვერზე
სერვერმა უნდა დაამატოს სწორი სათაურები თავის პასუხებს, შეცდომის პასუხების ჩათვლით.
თავად მოთხოვნისთვის გაგზავნეთ:
Access-Control-Allow-Origin: https://myapp.com(თქვენი ფრონტენდის ზუსტი წყარო, ბოლო სლეშის გარეშე)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, რომ ბრაუზერმა preflight გარკვეხანს ქეშში შეინახოს
უმეტეს ჩარჩოს აქვს პაკეტი ან პარამეტრი, რომელიც ამას აკეთებს. 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-ით არ უარყოფილიყო.
AI ბილდერში აღწერეთ დაყენება ზუსტად:
ფრონტენდი
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: დაამუშავეთ cookie-ები და credentials
თუ თქვენი ფრონტენდი cookie-ებს (მაგალითად შესვლის სესიას) სხვა წყაროზე აგზავნის, ორივე მხარემ უნდა დათანხმდეს:
- ფრონტენდი
fetch-ზე აყენებსcredentials: "include"-ს, ან axios-შიwithCredentials: true-ს. - სერვერი აგზავნის
Access-Control-Allow-Credentials: true-ს. - სერვერის
Access-Control-Allow-Originუნდა იყოს ზუსტი წყარო, და არა*.
წყაროებს შორის cookie-ებს ასევე სჭირდება SameSite=None; Secure, და ზოგი ბრაუზერი მესამე მხარის cookie-ებს უფრო მეტად ზღუდავს. ეს კიდევ ერთი მიზეზია, რომ მე-5 ნაბიჯში აღწერილი მიდგომა გირჩევნიათ.
ნაბიჯი 5: აირიდეთ CORS იმავე წყაროს დაყენებით
ხშირად ყველაზე სუფთა გამოსავალია საერთოდ არ გააკეთოთ წყაროებს შორის მოთხოვნები. მიაწოდეთ API იმავე წყაროდან, სადაც გვერდია, მაგალითად https://myapp.com/api/...-ზე:
- განვითარების დროს უმეტეს dev სერვერს შეუძლია პროქსირება. Vite-ის
server.proxyპარამეტრს შეუძლია/apiგადაამისამართოს თქვენს backend-ზე სხვა პორტზე, ასე რომ ბრაუზერი მხოლოდ ერთ წყაროსთან საუბრობს. - წარმოებაში გადაამისამართეთ
/apibackend-ზე თქვენი ჰოსტის rewrite ან proxy პარამეტრებით, ან ფრონტენდი და API ერთ სერვერზე მიაწოდეთ.
მაშინ ფრონტენდი ეძახის ფარდობით გზას, მაგალითად fetch("/api/orders"). წყაროებს შორის მოთხოვნა არ არის, არც წყაროებს შორის preflight და არც cookie-ების თავსატეხი. ეს ნიშნავს, რომ არ აკოდებთ API დომენს, რომელიც გადახედვასა და წარმოებას შორის განსხვავდება.
შეცვალე ფრონტენდი, რომ backend-ს ფარდობითი /api გზებით დაუძახოს სრული URL-ის ნაცვლად, და დააყენე dev პროქსი, რომ /api API სერვერზე გადავიდეს. შემდეგ წაშალე CORS პარამეტრები, რომლებიც აღარ გვჭირდება.
რა არ უნდა გააკეთოთ
mode: "no-cors"fetch-ში. ის არაფერს არ ავირიდებს; თქვენს კოდს ცარიელ, წაუკითხავ პასუხს აძლევს.- ბრაუზერის გაფართოებები, რომლებიც CORS-ს თიშავს. ისინი მხოლოდ თქვენს ბრაუზერს ცვლიან. ყველა ვიზიტორი მაინც შეცდომას დაინახავს.
- საჯარო „CORS proxy" სერვისები რეალური აპებისთვის. მათ შეუძლიათ ყველაფრის წაკითხვა და შეცვლა, რაც მათში გადის, და ისინი ხშირად ირთვება.
Access-Control-Allow-Origin: *API-ზე, რომელიც შესვლას იყენებს. ის credentials-თან ისედაც არ მუშაობს და კერძო მონაცემებისთვის არასწორი ნაგულისხმევია.- ნებისმიერი
Originსათაურის ასახვა უკან credentials-ის დაშვებით. ეს საშუალებას აძლევს ნებისმიერ ვებსაიტს, მომხმარებლის სახელით შესულ მოთხოვნები გააგზავნოს. გამოიყენეთ დაშვებული სიები.
გავრცელებული მიზეზები AI-ით აშენებულ აპებში
| სიტუაცია | გამოსავალი |
|---|---|
| ფრონტენდი მესამე მხარის API-ს საიდუმლო გასაღებით ეძახის | გადაიტანეთ მოთხოვნა backend-ზე |
| გადახედვაში მუშაობს, გამოქვეყნებულ დომენზე არა | დაამატეთ გამოქვეყნებული და მორგებული დომენის წყაროები დაშვებულ სიაში, ან გამოიყენეთ ფარდობითი /api გზები |
| შეცდომა მხოლოდ POST, PUT ან DELETE-ზე | preflight დამუშავებული არ არის; დაამატეთ OPTIONS დამუშავება და დაშვებული სათაურები |
| შეცდომა გამოჩნდა, შესვლის დამატების შემდეგ | credentials-ს სჭირდება ზუსტი წყარო და Allow-Credentials |
| „CORS შეცდომა", მაგრამ Network ჩანართში 500 ჩანს | ჯერ სერვერის შეცდომა გაასწორეთ |
API URL მყარად არის localhost-ზე დაწერილი | გამოიყენეთ ფარდობითი გზები ან გარემოს მიხედვით პარამეტრი |
CORS Mythex-ში
როცა Mythex პროექტს აქვს ვებსაიტი და API სერვერი, ორივე სერვისად მუშაობს იმავე პროექტში, და გადახედვაში ერთმანეთს შორის გადართვა შეგიძლიათ. თუ აგენტს სთხოვთ, რომ ფრონტენდი backend-ს ფარდობითი /api გზით მიმართავდეს, განვითარებაში პროქსირებით, უმეტეს CORS პრობლემას თავიდან აიცილებთ. თუ მაინც გჭირდებათ წყაროებს შორის მოთხოვნები, მიეცით აგენტს კონსოლის ზუსტი შეცდომა და ჩართული წყაროები. შედეგი შეამოწმეთ გამოქვეყნებულ აპზეც, რადგან მისი მისამართი განსხვავდება გადახედვისგან. იხილეთ დოკუმენტაციაში Multi-service apps და API backends, და ჩვენი სახელმძღვანელოები AI-ით აშენებული აპის გამართვა და frontend vs backend.
CORS საკონტროლო სია
- წაკითხულია სრული კონსოლის შეცდომა და ჩაშლილი მოთხოვნის სტატუს კოდი
- გამორიცხულია დამალული 404 ან 500
- საიდუმლო გასაღებიანი API-ები ეძახის backend-იდან და არა ბრაუზერიდან
- სერვერი აგზავნის
Access-Control-Allow-Origin-ს ზუსტი დაშვებული წყაროებით -
OPTIONSpreflight პასუხობს დაშვებული მეთოდებითა და სათაურებით, ავტორიზაციამდე - CORS სათაურები შეცდომის პასუხებზეც არის
- credentials: ზუსტი წყარო,
Allow-Credentials: true, სწორი cookie პარამეტრები - გადახედვის, გამოქვეყნებული და მორგებული დომენის წყაროები დაფარულია, ან გამოიყენება ფარდობითი
/apiგზები - არ არის
no-cors, საჯარო პროქსი ან ნებისმიერი წყაროს ასახვის მალსახმობები
კითხვები
რას ნიშნავს CORS შეცდომა?
თქვენმა გვერდმა, რომელიც ერთი წყაროდან ჩაიტვირთა, სხვა წყაროდან პასუხის წაკითხვა სცადა, და იმ სერვერის პასუხში არ იყო სათაურები, რომლებიც ამის უფლებას იძლევა. ბრაუზერი თქვენს კოდს პასუხის კითხვას უკრძალავს. გამოსავალი სერვერზეა, ან იმაზე, თუ როგორ არის მოთხოვნა მარშრუტიზებული, და არა ფრონტენდის კოდში.
შემიძლია CORS შეცდომის გასწორება ფრონტენდიდან?
სწორად არა. პარამეტრები როგორიცაა mode: 'no-cors' მხოლოდ პასუხს მალავს თქვენი კოდისგან. გასწორება ხდება იმით, რომ სერვერი სწორ Access-Control-Allow-Origin სათაურს აგზავნის, ან API-ს იძახებთ თქვენი backend-იდან ან იმავე წყაროს პროქსიდან.
უსაფრთხოა Access-Control-Allow-Origin: *?
ეს კარგია საჯარო მონაცემებისთვის, რომელთა წაკითხვაც ნებისმიერს შეუძლია, მაგალითად საჯარო API შესვლის გარეშე. მას cookie-ებთან ან სხვა credentials-თან ერთად ვერ გამოიყენებთ, და კერძო API-ებისთვის უნდა ჩამოთვალოთ ზუსტი დაშვებული წყაროები.
რატომ მუშაობს მოთხოვნა Postman-ში ან curl-ში, მაგრამ არა ბრაუზერში?
CORS-ს მხოლოდ ბრაუზერები ახორციელებენ. Postman და curl მას არ იყენებენ, ამიტომ მოთხოვნა იქ შეიძლება წარმატებული იყოს და ბრაუზერში გვერდის JavaScript-ის მიერ გაგზავნისას დაიბლოკოს.
რა არის preflight მოთხოვნა?
არა-მარტივი მოთხოვნებისთვის, მაგალითად JSON POST-ისთვის ან Authorization სათაურით მოთხოვნისთვის, ბრაუზერი ჯერ OPTIONS მოთხოვნას აგზავნის და სერვერს ეკითხება, რომელი მეთოდები და სათაურებია დაშვებული. თუ ეს OPTIONS მოთხოვნა ჩაიშალა ან სწორი სათაურები არ აქვს, ნამდვილი მოთხოვნა საერთოდ არ იგზავნება.