ما هو CORS؟
CORS (مشاركة الموارد عبر المصادر) هي آلية المتصفح التي تقرر ما إذا كان يمكن لصفحة من مصدر ما قراءة استجابة من مصدر آخر. يوافق الخادم عبر Access-Control-Allow-Origin والترويسات المرتبطة؛ وللطلبات ذات الترويسات المخصصة أو الأساليب غير البسيطة يرسل المتصفح أولاً طلب OPTIONS تمهيدياً. تحمي CORS المستخدمين داخل المتصفحات فقط — ولا تقيّد الخوادم أو curl أو تطبيقات الجوال.
- صفحة الويب
https://app.example.com - المتصفح
- واجهة API
api.example.com
- 1 من صفحة الويب إلى المتصفح: تستدعي واجهة API مع بيانات الاعتماد ترسل
AuthorizationوContent-TypePOST /v1/orders - 2 المتصفح داخليًا: هل يلزم طلب تمهيدي؟ نعم:
AuthorizationوContent-Typeبقيمة JSON تقعان خارج القائمة الآمنة في CORS - 3 من المتصفح إلى واجهة API: الطلب التمهيدي مع
OriginوAccess-Control-Request-MethodوAccess-Control-Request-HeadersOPTIONS /v1/orders - 4 من واجهة API إلى المتصفح: استجابة الطلب التمهيدي ردّ الحالة وترويسات
Access-Control-Allow-* - 5 المتصفح داخليًا: يفحص استجابة الطلب التمهيدي المطلوب: حالة 2xx، والترويستان في
Allow-Headers، وAllow-Credentials: true، وAllow-Originبالأصل نفسه بالضبط لا* - 6 من المتصفح إلى واجهة API: الطلب الفعلي لا يُرسل إلا إذا نجح الطلب التمهيدي، ومعه
Originوملفات تعريف الارتباط أوAuthorizationPOST /v1/orders - 7 من واجهة API إلى المتصفح: الاستجابة ردّ مع ترويسات
Access-Control-Allow-*الخاصة بها - 8 المتصفح داخليًا: يفحص الاستجابة المطلوب:
Allow-Credentials: true، وAllow-Originبالأصل نفسه بالضبط لا* - 9 من المتصفح إلى صفحة الويب: الاستجابة، أو خطأ عام ردّ إذا فشل أي فحص، تبقى الاستجابة مخفية عن الصفحة
النتيجة: في المثال تجيب واجهة API بـ Access-Control-Allow-Origin: * ولا تذكر Authorization في Allow-Headers، فيكون الحكم «محظور» (Blocked). فشل
وفق معيار Fetch. طلب GET أو HEAD أو POST الذي لا يحمل إلا ترويسات من القائمة الآمنة في CORS يتخطّى الخطوات من 3 إلى 5، ولا تهمّ ترويسة Allow-Methods إلا مع الطرق الأخرى. يرسل مرحّل الأداة الطلبين، ثم تطبّق الأداة هذه الفحوص على ترويساتهما.
كيفية استخدام فاحص CORS
- أدخل عنوان URL العام لواجهة API وأصل تطبيق الويب الذي سيستدعيها.
- اختر الطريقة واذكر ترويسات الطلب التي سيرسلها التطبيق (Authorization وContent-Type…).
- شغّل الاختبار واقرأ الحكم؛ تحدّد قائمة «السبب» بالضبط الترويسة التي ستجعل المتصفح يحظر الطلب.
- أصلح إعدادات الخادم وأعد التشغيل حتى يصبح الحكم «مسموح».
مزايا فاحص CORS
- يرسل طلباً تمهيدياً (OPTIONS) يعلن الطريقة وترويسات الطلب التي تختارها، ثم الطلب الفعلي بالأصل (Origin) الذي تحدّده
- حكم مشروح خطوة بخطوة: تطابق الأصل، وبيانات الاعتماد، والطرق والترويسات المسموح بها، وحالة الطلب التمهيدي، وmax-age
- يكشف متى يلزم طلب تمهيدي وفق قواعد القائمة الآمنة في CORS
- جداول لترويسات استجابة الطلب التمهيدي والطلب الفعلي مع الشروحات
- يحذّر من حرف البدل (*) مع بيانات الاعتماد ومن غياب Vary: Origin
مثال على فاحص CORS
اختبار طلب POST مع بيانات الاعتماد (مقتطف من النتيجة)
الإدخال:
URL: https://api.example.com/v1/orders · Origin: https://app.example.com · Method: POST · Headers: Authorization, Content-Typeالنتيجة:
Result: Blocked
Preflight needed: Yes (OPTIONS) · Preflight status: 204
Access-Control-Allow-Origin is "*" but the request is credentialed; browsers reject the wildcard with credentials.
Access-Control-Allow-Headers does not list: Authorization.الأسئلة الشائعة حول فاحص CORS
متى يرسل المتصفح طلباً تمهيدياً؟
لأي طريقة غير GET وHEAD وPOST، ولترويسات الطلب الخارجة عن القائمة الآمنة في CORS، وهي: Accept وAccept-Language وContent-Language، وContent-Type بالقيم application/x-www-form-urlencoded أو multipart/form-data أو text/plain فقط، وRange بنطاق بايتات واحد فقط. لذا يستدعي Content-Type: application/json طلباً تمهيدياً. تخبرك الأداة ما إذا كانت تركيبتك تستدعي إرسال OPTIONS؛ ولأنها تتلقى أسماء الترويسات فقط، فإنها تعامل أي Content-Type أو Range تذكره على أنه يحمل قيمة خارج القائمة الآمنة. احذفه من القائمة لاختبار طلب نموذج أو طلب text/plain.
لماذا يُحظر طلبي رغم أن Access-Control-Allow-Origin يساوي *؟
يُرفض حرف البدل عندما يستخدم الطلب بيانات الاعتماد (ملفات تعريف الارتباط أو Authorization مع credentials: "include"). أعد بدلاً من ذلك الأصل نفسه بالضبط، وأضف Access-Control-Allow-Credentials: true وVary: Origin.
لماذا تستدعي الأداة واجهة API من خادم بدلاً من متصفحي؟
يخفي المتصفح الاستجابة المحظورة، فلن ترى سوى خطأ عام. ينفّذ المرحّل (relay) طلب OPTIONS والطلب الفعلي بترويسة Origin التي اخترتها ويعيد ترويسات Access-Control-* الخام حتى يمكن شرح الحكم.
هل يمكنني اختبار localhost أو واجهة API داخلية؟
لا. يرفض المرحّل العناوين الخاصة وعناوين الاسترجاع (loopback) وعناوين الارتباط المحلي (link-local) لأسباب أمنية. اعرض واجهة API عبر نفق (مثل مضيف تجريبي عام) لاختبارها.
ملاحظات تقنية
يعيد المرحّل إنتاج خوارزمية المتصفح وفق معيار Fetch: يُرسل الطلب التمهيدي مع Access-Control-Request-Method وAccess-Control-Request-Headers، ويُرسل الطلب الفعلي مع ترويسة Origin. ويُدمج حكم جانب الخادم مع إعادة تقييم محلية بحيث يُوضَّح كل سبب صراحةً، بما في ذلك الحالات التي يعدّها المرحّل مسموحاً بها لكنها تفشل مع الطلبات ذات بيانات الاعتماد.
المراجع
- Fetch Standardيعرّف CORS: طلبات التحقق المسبق وترويسات Access-Control-* والاستجابات التي يسمح المتصفح للصفحة برؤيتها.
- Cross-Origin Resource Sharing (CORS) — MDNكيف يعمل CORS عملياً: الطلبات البسيطة مقابل الطلبات ذات التحقق المسبق، وبيانات الاعتماد، والأخطاء التي تبلّغ عنها المتصفحات.