الخطأ“تم حظر الوصول للجلب عند ‘…’ من الأصل ‘…’ بواسطة سياسة CORS: لا يوجد رأس ‘Access-Control-Allow-Origin'” يعد أحد أكثر أخطاء تطوير الويب شيوعًا. يتم فرضه بواسطة المتصفح كآلية أمنية. هنا كل الأسباب والإصلاح.
📋 Table of Contents
لماذا يوجد CORS (الفهم المطلوب)
تمنع CORS (مشاركة الموارد عبر الأصل) مواقع الويب الضارة من تقديم طلبات إلى واجهة برمجة التطبيقات الخاصة بالبنك الذي تتعامل معه باستخدام ملفات تعريف الارتباط التي تم تسجيل الدخول إليها. بدون CORS، يمكن لزيارة evil.com إجراء مكالمات API بصمت إلى yourbank.com باستخدام ملفات تعريف الارتباط الخاصة بجلستك. يفرض المتصفح CORS – تعلن الخوادم عن الأصول المسموح بها.
CORS هي ميزة أمان للمتصفح – ينطبق فقط على الطلبات التي يبدأها المتصفح. لا تتأثر طلبات curs وpostman وطلبات خادم إلى خادم بـ CORS.
الإصلاح 1: Express.js – استخدام حزمة cors
npm install cors
const express = require('express');
const cors = require('cors');
const app = express();
// ✅ Allow specific origin (recommended for production)
app.use(cors({
origin: 'https://yourfrontend.com',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // required if frontend sends cookies/auth headers
}));
// ✅ Allow multiple origins
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error(`Origin ${origin} not allowed by CORS`));
}
},
credentials: true,
}));
// ❌ Allow all origins (never in production with credentials)
app.use(cors({ origin: '*' }));
// Note: wildcard '*' cannot be used with credentials: true
الإصلاح 2: رؤوس CORS اليدوية في Express
// Without the cors package
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://yourfrontend.com');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
// Handle preflight requests
if (req.method === 'OPTIONS') {
return res.status(204).end();
}
next();
});
الإصلاح 3: Nginx Reverse Proxy
location /api/ {
proxy_pass http://localhost:3000/;
# CORS headers
add_header 'Access-Control-Allow-Origin' 'https://yourfrontend.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
# Handle preflight
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://yourfrontend.com';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
الإصلاح 4: الواجهة الأمامية – وضع بيانات الاعتماد
// ❌ Fetch without credentials — cookies not sent
const res = await fetch('https://api.example.com/user');
// ✅ Include credentials (cookies, authorization headers)
const res = await fetch('https://api.example.com/user', {
credentials: 'include', // send cookies cross-origin
});
// For axios:
axios.defaults.withCredentials = true;
// Or per-request:
axios.get('/api/user', { withCredentials: true });
هام: متىcredentials: 'include'يجب أن يقوم الخادم بتعيينAccess-Control-Allow-Origin إلى الأصل المحدد (ليس*) وAccess-Control-Allow-Credentials: true.
فهم طلبات الاختبار المبدئي
بالنسبة للطلبات “غير البسيطة” (PUT، DELETE، الرؤوس المخصصة، نص التطبيق/json)، يرسل المتصفح طلب اختبار مبدئي OPTIONS أولاً للتحقق مما إذا كان الطلب الفعلي مسموحًا به. إذا فشل الاختبار المبدئي، فلن يتم تنفيذ الطلب الفعلي أبدًا.
// Browser sends OPTIONS before POST with JSON body:
OPTIONS /api/users HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
// Server must respond:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400 // cache preflight for 24 hours
وكيل التطوير (تجنب CORS أثناء التطوير)
// vite.config.ts — proxy /api to backend during dev
export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
}
}
}
};
// package.json (Create React App) — proxy all /api requests
{
"proxy": "http://localhost:3000"
}
يقدم الوكيل طلبات من نفس مصدر الواجهة الأمامية (من خادم التطوير)، متجاوزًا CORS بالكامل أثناء التطوير – دون المساس بأمان الإنتاج.
أخطاء شائعة
// ❌ Mistake 1: CORS headers on wrong route
app.get('/api/data', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.json(data);
});
// OPTIONS preflight hits a different handler that doesn't have CORS headers
// ❌ Mistake 2: Setting headers after response sent
app.use(cors());
app.get('/data', authenticate, (req, res) => {
res.header('Access-Control-Allow-Origin', '*'); // Too late if cors() runs first
});
// ❌ Mistake 3: Multiple conflicting CORS headers
// Browser rejects when two Access-Control-Allow-Origin headers present
// Don't set CORS in both nginx AND Express — pick one place
الأسئلة المتداولة
س: هل يمكنني تعطيل CORS في المتصفح للتطوير؟
ج: نعم:open -a "Google Chrome" --args --disable-web-security --user-data-dir="/tmp/chrome-dev". فقط للمطورين المحليين – لا تتصفح أبدًا المواقع الحقيقية التي تحمل هذه العلامة. يعد استخدام الوكيل أكثر أمانًا ولا يتطلب تعطيل الأمان.
س: لماذا يعمل في Postman وليس في المتصفح؟
ج: يتم فرض CORS بواسطة المتصفحات فقط. يرسل ساعي البريد الطلب مباشرة دون فحص CORS للمتصفح. يؤكد هذا أن الخادم الخاص بك يعمل، كل ما عليك فعله هو إضافة رؤوس CORS.
س: هل يجب علي إضافة رؤوس CORS في التطبيق أم الوكيل العكسي؟
ج: مكان واحد فقط. إذا كنت تستخدم nginx، أضف رؤوسًا في nginx ولا تضيفها في Express (يمنع الرؤوس المكررة). في حالة النشر إلى خدمة دون تحكم nginx، أضف Express.
س: لماذا تعمل واجهة برمجة التطبيقات (API) الخاصة بي من نفس الأصل ولكن ليس عبر الأصل؟
ج: هذا بالضبط ما يمنعه CORS — تتطلب الطلبات عبر الأصل إذنًا صريحًا من الخادم. لا تحتاج الطلبات ذات المصدر نفسه (الواجهة الأمامية وواجهة برمجة التطبيقات على نفس المجال/المنفذ) إلى رؤوس CORS.
س: هل يمكنني استخدام خدمة وكيل CORS؟
ج: بالنسبة لتطوير النماذج الأولية، تعمل خدمات مثل cors-anywhere. لا يتعلق الأمر بالإنتاج أبدًا — فأنت ترسل جميع طلبات واجهة برمجة التطبيقات (API) الخاصة بك من خلال خدمة تابعة لجهة خارجية. قم بإصلاح CORS بشكل صحيح على الخادم الخاص بك.
الخلاصة
إصلاح CORS عن طريق إضافةAccess-Control-Allow-Origin الرؤوس الموجودة على الخادم الخاص بك – وليس عن طريق تعطيل CORS أو استخدام المكونات الإضافية للمتصفح. بالنسبة إلى Express.js، فإنcors تتعامل حزمة npm مع جميع الحالات بشكل نظيف. بالنسبة إلى Nginx، أضف رؤوسًا على مستوى الوكيل. للتطوير، استخدم تكوين وكيل Vite لتجنب CORS تمامًا. حدد دائمًا الأصول الدقيقة بدلاً من أحرف البدل* في الإنتاج، وخاصة عند استخدام أوراق الاعتماد.
🔗 Share this article
✍️ Leave a Comment