CORS এরর কীভাবে ঠিক করবেন (এবং কেন হয়)
CORS এরর মানে আপনার ওয়েব পেজ এমন একটি রেসপন্স পড়তে চেয়েছে যা অন্য অরিজিন থেকে এসেছে (অন্য ডোমেইন, পোর্ট বা প্রোটোকল), আর সেই সার্ভার জানায়নি যে অনুমতি আছে। ব্যবহারকারীদের রক্ষা করতে ব্রাউজার রেসপন্সটি আটকে দেয়। আপনি সার্ভারে ঠিক করেন, আপনার সাইটের অরিজিনের জন্য Access-Control-Allow-Origin হেডার ফেরত দিয়ে এবং OPTIONS preflight অনুরোধ সামলিয়ে; অথবা একই অরিজিনে আপনার নিজের ব্যাকএন্ডের মাধ্যমে অনুরোধ পাঠিয়ে এড়িয়ে যান।
ওয়েব ডেভেলপমেন্টের সবচেয়ে বিভ্রান্তিকর এররগুলোর একটি এটি, কারণ অনুরোধটি প্রায়ই সার্ভারে ঠিকই পৌঁছায়। এই গাইড বলে কী ঘটছে এবং প্রতিটি রূপ কীভাবে ঠিক করতে হয়।
"অরিজিন" মানে কী
অরিজিন হলো প্রোটোকল, ডোমেইন ও পোর্টের সমষ্টি:
| 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 ঠিক আছে।
ধাপ ১: সঠিক এররটি পড়ুন
ডেভেলপার টুল খুলুন (ডান ক্লিক → 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' | আপনি কুকি পাঠাচ্ছেন, আর সার্ভার * দিয়ে উত্তর দিয়েছে |
Request header field authorization is not allowed | সার্ভার Access-Control-Allow-Headers-এ ওই হেডারটি তালিকাভুক্ত করেনি |
এরপর Network ট্যাব খুলুন, ব্যর্থ অনুরোধটি (এবং তার আগের যেকোনো OPTIONS অনুরোধ) খুঁজুন, আর তার স্ট্যাটাস কোড ও রেসপন্স হেডার দেখুন।
প্রথমে স্ট্যাটাস কোড দেখুন। অনেক "CORS এরর" আসলে ছদ্মবেশী সার্ভার এরর। সার্ভার ক্র্যাশ করলে বা 404 দিলে তার এরর রেসপন্সে প্রায়ই CORS হেডার থাকে না, তাই ব্রাউজার আসল সমস্যার বদলে CORS জানায়। 500 বা 404 ঠিক করুন, তাহলে CORS এররও মিলিয়ে যেতে পারে।
ধাপ ২: সত্যিই ব্রাউজার থেকে এই API কল করা উচিত কি না সিদ্ধান্ত নিন
হেডার যোগ করার আগে জিজ্ঞেস করুন: ব্রাউজার কি সরাসরি এই API কল করা উচিত?
- গোপন কী দরকার এমন তৃতীয় পক্ষের API (OpenAI, Stripe-এর সিক্রেট কী, বেশিরভাগ ইমেইল সার্ভিস) কখনো ব্রাউজার থেকে কল করা উচিত নয়। কী প্রতিটি দর্শকের কাছে দৃশ্যমান হবে। বরং আপনার ব্যাকএন্ড থেকে কল করুন; তাহলে CORS সমস্যাটি চলে যায়, কারণ সার্ভার-টু-সার্ভার অনুরোধে CORS প্রযোজ্য নয়। দেখুন API কী নিরাপদ রাখার উপায়।
- তৃতীয় পক্ষের এমন API যা আপনার নিয়ন্ত্রণে নেই এবং CORS হেডার পাঠায় না, তা আপনার দিক থেকে ঠিক করা যায় না। আপনার ব্যাকএন্ড থেকে কল করুন।
- আপনার নিজের API সঠিকভাবে কনফিগার করে ঠিক করা যায়। নিচে চালিয়ে যান।
ধাপ ৩: আপনার সার্ভারে ঠিক করুন
সার্ভারকে তার রেসপন্সে সঠিক হেডার যোগ করতে হবে, এরর রেসপন্সসহ।
আসল অনুরোধের জন্য পাঠান:
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-এর ফ্রন্ট এন্ডhttps://api.myapp.com-এর API কল করছে এবং "Response to preflight request doesn't pass access control check" পাচ্ছে। API-তে CORS কনফিগার করো যাতে ঠিকhttps://myapp.comএবং প্রিভিউ অরিজিন অনুমতি পায়, Content-Type ও Authorization হেডারসহ GET, POST, PATCH, DELETE অনুমোদিত হয়, OPTIONS অথেনটিকেশনের আগে সামলানো হয়, আর এরর রেসপন্সেও CORS হেডার থাকে।
ধাপ ৪: কুকি ও credentials সামলান
ফ্রন্ট এন্ড যদি অন্য অরিজিনে কুকি (যেমন লগইন সেশন) পাঠায়, তবে দুই পক্ষকেই একমত হতে হবে:
- ফ্রন্ট এন্ড
fetch-এcredentials: "include"সেট করে, অথবা axios-এwithCredentials: true। - সার্ভার
Access-Control-Allow-Credentials: trueপাঠায়। - সার্ভারের
Access-Control-Allow-Originঅবশ্যই হুবহু অরিজিন হতে হবে,*নয়।
ক্রস-সাইট কুকিতে কুকিতে SameSite=None; Secure লাগে, এবং কিছু ব্রাউজার তৃতীয়-পক্ষের কুকি আরও সীমিত করে। ধাপ ৫-এর পথটি বেছে নেওয়ার আরেকটি কারণ এটিই।
ধাপ ৫: একই-অরিজিন সেটআপ দিয়ে CORS এড়িয়ে চলুন
প্রায়ই সবচেয়ে পরিষ্কার সমাধান হলো আদৌ ক্রস-অরিজিন অনুরোধ না করা। পেজের একই অরিজিন থেকে API পরিবেশন করুন, যেমন https://myapp.com/api/...-এ:
- ডেভেলপমেন্টে বেশিরভাগ ডেভ সার্ভার প্রক্সি করতে পারে। Vite-এর
server.proxyসেটিং/api-কে অন্য পোর্টের ব্যাকএন্ডে পাঠাতে পারে, তাই ব্রাউজার কেবল একটি অরিজিনের সঙ্গে কথা বলে। - প্রোডাকশনে আপনার হোস্টের rewrite বা প্রক্সি সেটিং দিয়ে
/api-কে ব্যাকএন্ডে রাউট করুন, অথবা ফ্রন্ট ও API একই সার্ভারে পরিবেশন করুন।
তখন ফ্রন্ট এন্ড fetch("/api/orders")-এর মতো আপেক্ষিক পাথে কল করে। কোনো ক্রস-অরিজিন অনুরোধ নেই, অরিজিন জুড়ে কোনো preflight নেই, আর কুকির ঝামেলাও নেই। এর মানে প্রিভিউ ও প্রোডাকশনের মধ্যে আলাদা থাকা একটি API ডোমেইন হার্ড-কোড করতে হয় না।
ফ্রন্ট এন্ডকে সম্পূর্ণ URL-এর বদলে আপেক্ষিক /api পাথে ব্যাকএন্ড কল করতে বদলাও, এবং একটি ডেভ প্রক্সি সেট করো যাতে /api API সার্ভারে পাঠানো হয়। তারপর আর যেসব CORS সেটিং লাগে না সেগুলো সরাও।
যা করবেন না
fetch-এmode: "no-cors"। এটি কিছুই বাইপাস করে না; আপনার কোডকে একটি খালি, অপঠনযোগ্য রেসপন্স দেয়।- CORS বন্ধ করে দেয় এমন ব্রাউজার এক্সটেনশন। এগুলো শুধু আপনার ব্রাউজার বদলায়। প্রতিটি দর্শক তবু এরর দেখবে।
- আসল অ্যাপের জন্য পাবলিক "CORS প্রক্সি" সার্ভিস। এগুলো তাদের মধ্য দিয়ে যাওয়া সবকিছু পড়তে ও বদলাতে পারে, এবং এগুলো বন্ধ হয়ে যেতে পারে।
- লগইন ব্যবহার করা API-তে
Access-Control-Allow-Origin: *। credentials-এর সঙ্গে এটি এমনিতেই কাজ করে না, এবং প্রাইভেট ডেটার জন্য এটি ভুল ডিফল্ট। - যেকোনো
Originহেডার ফিরিয়ে দেওয়া credentials অনুমতি দিয়ে। এতে যেকোনো ওয়েবসাইট আপনার ব্যবহারকারীর পক্ষে লগইন করা অনুরোধ করতে পারে। একটি অনুমোদন-তালিকা (allowlist) ব্যবহার করুন।
AI দিয়ে বানানো অ্যাপের সাধারণ কারণ
| পরিস্থিতি | সমাধান |
|---|---|
| ফ্রন্ট এন্ড সিক্রেট কী সহ তৃতীয় পক্ষের API কল করছে | কলটি ব্যাকএন্ডে সরান |
| প্রিভিউতে কাজ করে, প্রকাশিত ডোমেইনে ব্যর্থ | প্রকাশিত ও কাস্টম-ডোমেইন অরিজিন অনুমোদন-তালিকায় যোগ করুন, অথবা আপেক্ষিক /api পাথ ব্যবহার করুন |
| শুধু POST, PUT বা DELETE-এ এরর | preflight সামলানো হয়নি; OPTIONS হ্যান্ডলিং ও অনুমোদিত হেডার যোগ করুন |
| লগইন যোগ করার পর এরর এসেছে | credentials-এর জন্য হুবহু অরিজিন ও Allow-Credentials দরকার |
| "CORS এরর" কিন্তু Network ট্যাবে 500 দেখা যায় | আগে সার্ভার এরর ঠিক করুন |
API URL localhost-এ হার্ড-কোড করা | আপেক্ষিক পাথ বা প্রতি-এনভায়রনমেন্ট সেটিং ব্যবহার করুন |
Mythex-এ CORS
যখন কোনো Mythex প্রজেক্টে ওয়েবসাইট ও API সার্ভার থাকে, দুটোই একই প্রজেক্টে সার্ভিস হিসেবে চলে, আর প্রিভিউতে আপনি এদের মধ্যে বদলাতে পারেন। এজেন্টকে বলুন ফ্রন্ট এন্ড যেন আপেক্ষিক /api পাথের মাধ্যমে ব্যাকএন্ড কল করে, ডেভেলপমেন্টে প্রক্সি হয়ে, তাহলে বেশিরভাগ CORS সমস্যা এড়ানো যায়। যদি সত্যিই ক্রস-অরিজিন কল দরকার হয়, কনসোল থেকে হুবহু এররটি এবং জড়িত অরিজিনগুলো এজেন্টকে দিন। প্রকাশিত অ্যাপেও ফলাফল যাচাই করুন, কারণ তার ঠিকানা প্রিভিউর থেকে আলাদা। ডকসে দেখুন মাল্টি-সার্ভিস অ্যাপ এবং API ব্যাকএন্ড, আর আমাদের গাইড AI দিয়ে বানানো অ্যাপের ডিবাগ করা ও ফ্রন্ট এন্ড বনাম ব্যাকএন্ড।
CORS চেকলিস্ট
- পুরো কনসোল এরর ও ব্যর্থ অনুরোধের স্ট্যাটাস কোড পড়া হয়েছে
- লুকানো 404 বা 500 বাদ দেওয়া হয়েছে
- সিক্রেট-কী API ব্রাউজার থেকে নয়, ব্যাকএন্ড থেকে কল হচ্ছে
- সার্ভার হুবহু অনুমোদিত অরিজিনসহ
Access-Control-Allow-Originপাঠায় -
OPTIONSpreflight অনুমোদিত মেথড ও হেডারসহ, অথেনটিকেশনের আগে উত্তর পায় - এরর রেসপন্সেও CORS হেডার আছে
- Credentials: হুবহু অরিজিন,
Allow-Credentials: true, সঠিক কুকি সেটিং - প্রিভিউ, প্রকাশিত ও কাস্টম-ডোমেইন অরিজিন সবই ঢাকা, অথবা আপেক্ষিক
/apiপাথ ব্যবহৃত -
no-cors, পাবলিক প্রক্সি, বা যেকোনো-অরিজিন-ফেরত শর্টকাট নেই
প্রশ্নোত্তর
CORS এরর মানে কী?
আপনার পেজ এক অরিজিন থেকে লোড হয়ে অন্য অরিজিন থেকে একটি রেসপন্স পড়তে চেয়েছে, আর সেই সার্ভারের রেসপন্সে অনুমতি দেওয়ার হেডার ছিল না। ব্রাউজার আপনার কোডকে রেসপন্স পড়তে দেয় না। সমাধান সার্ভারে, অথবা অনুরোধটি কীভাবে রাউট হচ্ছে তাতে; ফ্রন্ট এন্ড কোডে নয়।
ফ্রন্ট এন্ড থেকে কি CORS এরর ঠিক করা যায়?
ঠিকভাবে না। mode: 'no-cors'-এর মতো সেটিং কেবল রেসপন্সটি আপনার কোড থেকে লুকায়। সার্ভারকে সঠিক Access-Control-Allow-Origin হেডার পাঠাতে বলে, অথবা আপনার নিজের ব্যাকএন্ড বা একই-অরিজিন প্রক্সির মাধ্যমে API কল করে ঠিক করতে হয়।
Access-Control-Allow-Origin: * কি নিরাপদ?
যে পাবলিক ডেটা যে কেউ পড়তে পারে, যেমন লগইন ছাড়া পাবলিক API, তার জন্য ঠিক আছে। এটি কুকি বা অন্য credentials-এর সঙ্গে ব্যবহার করা যায় না, আর প্রাইভেট API-এর জন্য অনুমোদিত অরিজিনগুলো হুবহু তালিকাভুক্ত করা উচিত।
আমার অনুরোধ Postman বা curl-এ কাজ করে, কিন্তু ব্রাউজারে কেন করে না?
CORS শুধু ব্রাউজারই প্রয়োগ করে। Postman বা curl-এর মতো টুল এটি মানে না, তাই পেজের JavaScript অনুরোধটি করলে সেখানে সফল হতে পারে এবং তবু আটকে যেতে পারে।
preflight অনুরোধ কী?
সহজ নয় এমন অনুরোধের জন্য, যেমন JSON POST বা Authorization হেডারসহ অনুরোধ, ব্রাউজার আগে একটি OPTIONS অনুরোধ পাঠায় এবং জিজ্ঞেস করে কোন মেথড ও হেডার অনুমোদিত। সেই OPTIONS অনুরোধ ব্যর্থ হলে বা সঠিক হেডার না থাকলে আসল অনুরোধ আর পাঠানোই হয় না।