رأس Access-Control-Allow-Origin: شرح مفصل وحل مشكلات CORS الشائعة
في عالم تطوير الويب، قد تواجه أحيانًا رسالة خطأ مزعجة في وحدة تحكم المتصفح (console) عند محاولة جلب بيانات من واجهة برمجة تطبيقات (API). غالبًا ما تبدو هذه الرسالة كالتالي:
Access to fetch at 'http://somesite.com' from origin 'http://yoursite.com' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value that is not equal to the supplied origin
إذا صادفت هذا الخطأ من قبل، فأنت لست وحدك. إنه مؤشر شائع على مشكلة تتعلق بسياسة أمان المتصفح المعروفة باسم CORS. في هذا المقال، سنتعمق في فهم سبب حدوث هذا الخطأ وكيف يمكنك معالجته بفعالية باستخدام رأس Access-Control-Allow-Origin.
ما هو رأس Access-Control-Allow-Origin؟
يُعد Access-Control-Allow-Origin أحد رؤوس (headers) استجابة بروتوكول HTTP، وهو جزء أساسي من آلية مشاركة الموارد عبر النطاقات (CORS)، والتي تعني Cross-Origin Resource Sharing. تتيح هذه الآلية للمتصفحات السماح لموقع ويب يعمل على نطاق (Origin) معين (لنسميه النطاق A) بطلب موارد من نطاق آخر (النطاق B).
فهم “النطاق” (Origin)
النطاق ليس مجرد اسم المضيف (hostname)؛ بل هو مزيج من البروتوكول (scheme)، واسم المضيف، ورقم المنفذ (port). على سبيل المثال، http://mysite.example.com:8080/ يمثل نطاقًا كاملاً. إذا اختلف أي جزء من هذه الأجزاء الثلاثة بين طلب المورد والمورد نفسه، فإن المتصفح يعتبرهما نطاقين مختلفين.
لنفترض أن لديك موقعًا على النطاق A (مثل http://mysite.com) وترغب في جلب موارد من النطاق B (مثل http://yoursite.com). لحماية أمن المستخدمين، لن يسمح المتصفح افتراضيًا بالوصول إلى الموارد من http://yoursite.com وسيحظر هذا الطلب. لكي يتمكن النطاق A من الوصول إلى هذه الموارد، يجب على النطاق B أن يخبر المتصفح صراحةً أنه لا توجد مشكلة في السماح بالوصول.
توضح الصورة التالية مبدأ عمل CORS بوضوح:

بمساعدة CORS، تسمح المتصفحات للنطاقات المختلفة بمشاركة الموارد فيما بينها. هناك عدة رؤوس تسمح بمشاركة الموارد عبر النطاقات، لكن رأس Access-Control-Allow-Origin هو الأهم. يحدد هذا الرأس للمتصفح النطاقات المسموح لها بتلقي الطلبات من هذا الخادم.
من المسؤول عن تعيين رأس Access-Control-Allow-Origin؟
لفهم من يجب عليه تعيين هذا الرأس، دعنا نتخيل السيناريو التالي:
أنت تتصفح موقع ويب مخصص لعرض الأغاني والاستماع إليها. يحاول هذا الموقع بشكل خبيث إجراء اتصال بخدمة مصرفك في الخلفية دون علمك. من يملك القدرة النهائية على منع هذا الموقع الخبيث من سرقة بياناتك المصرفية؟ بالطبع، البنك!
لذا، يجب على البنك (الذي يمثل النطاق الذي يقدم الموارد الحساسة) حماية موارده عن طريق تعيين رأس Access-Control-Allow-Origin كجزء من استجابته. تذكر دائمًا: النطاق المسؤول عن تقديم الموارد هو من يحتاج إلى تعيين هذا الرأس.
كيفية استخدام رأس Access-Control-Allow-Origin ومتى يتم تمريره
يتم تعيين رأس Access-Control-Allow-Origin في استجابة الخادم لتحديد النطاقات المسموح لها بالوصول إلى موارده. إليك أمثلة على القيم التي يمكنك تعيينها:
Access-Control-Allow-Origin: *: هذه القيمة تسمح لأي نطاق بتقديم طلبات إلى الخادم. يجب استخدامها بحذر شديد وفي حالات محددة فقط، حيث إنها تفتح مواردك لأي موقع ويب.Access-Control-Allow-Origin: http://mysite.com: هذه القيمة تسمح فقط للطلبات القادمة من النطاقhttp://mysite.comبالوصول إلى الموارد. هذه هي الطريقة الأكثر أمانًا وتوصى بها عادةً.
مثال عملي: رؤية CORS في العمل
دعنا نلقي نظرة على مثال عملي لفهم كيفية عمل هذا الرأس. يمكنك مراجعة الكود على مستودع GitHub الخاص بالمؤلف الأصلي.
سنقوم بإنشاء خادم على النطاق A (http://localhost:8000) والذي سيرسل سلسلة نصية Hello إلى نقطة نهاية /api. بعد ذلك، سنقوم بإنشاء عميل على النطاق B (http://localhost:3000) لاستدعاء نقطة النهاية هذه باستخدام الدالة fetch. نتوقع أن نرى السلسلة Hello التي يرسلها النطاق A في وحدة تحكم المتصفح (console) الخاصة بالنطاق B.
إعداد الخادم (النطاق A)
لنفترض أن لدينا خادمًا يعمل على http://localhost:8000 ويقدم هذا المورد على نقطة النهاية /api. يرسل الخادم استجابة مع رأس Access-Control-Allow-Origin.
const express = require("express");
const app = express();
const port = process.env.SERVER_PORT || 8000;
// Add Access Control Allow Origin headers
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "https://yoursite.com");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get("/api", (req, res) => {
res.json("Hello");
});
app.listen(port, () => console.log(`Listening on port ${port}`));
إعداد العميل (النطاق B)
على جانب العميل، يمكنك استدعاء نقطة النهاية هذه باستخدام fetch كالتالي:
fetch('http://localhost:8000/api')
.then(res => res.json())
.then(res => console.log(res));
الآن، افتح وحدة تحكم المتصفح (browser’s console) لترى النتيجة. نظرًا لأن الرأس Access-Control-Allow-Origin مضبوط حاليًا للسماح بالوصول فقط من https://yoursite.com، سيقوم المتصفح بحظر الوصول إلى المورد وسترى خطأً في وحدة التحكم الخاصة بك.

إصلاح المشكلة
لإصلاح هذا، قم بتغيير إعداد الرأس في كود الخادم ليصبح كالتالي:
res.setHeader("Access-Control-Allow-Origin", "*");
الآن، تحقق من وحدة تحكم المتصفح مرة أخرى، وستتمكن من رؤية السلسلة Hello بنجاح. هذا يوضح كيف أن تغيير قيمة رأس Access-Control-Allow-Origin يؤثر بشكل مباشر على سياسة الوصول بين النطاقات.
الخلاصة التقنية
يُعد رأس Access-Control-Allow-Origin حجر الزاوية في أمان الويب الحديث، فهو يمثل خط الدفاع الأول ضد الهجمات العابرة للنطاقات (Cross-Site Scripting – XSS) وغيرها من الثغرات الأمنية التي تستغل مشاركة الموارد. فهم كيفية عمل CORS وتطبيق رأس Access-Control-Allow-Origin بشكل صحيح أمر بالغ الأهمية لأي مطور يتعامل مع واجهات برمجة التطبيقات أو يخدم محتوى من نطاقات متعددة. بينما توفر القيمة * مرونة كاملة، يجب استخدامها بحذر شديد وفي بيئات التطوير فقط، أو عند تقديم موارد عامة غير حساسة. في بيئات الإنتاج، يُفضل دائمًا تحديد النطاقات الموثوقة صراحةً لضمان أقصى درجات الأمان والتحكم في الوصول إلى الموارد الحساسة.