إضافة دعم CORS إلى خادم وكيل لواجهة برمجة التطبيقات

أنت الآن بصدد الاطّلاع على مستندات Apigee Edge.
انتقِل إلى مستندات Apigee X.
info

مشاركة الموارد المتعدّدة المصادر (CORS) هي آلية عادية تتيح لطلبات JavaScript XMLHttpRequest (XHR)‎ التي يتم تنفيذها في صفحة ويب التفاعل مع موارد من نطاقات غير تابعة للمصدر. مشاركة الموارد المتعدّدة المصادر (CORS) هي حلّ شائع التنفيذ لسياسة المصدر نفسه التي تفرضها جميع المتصفحات. على سبيل المثال، إذا أجريت طلب XHR إلى Twitter API من رمز JavaScript يتم تنفيذه في متصفحك، سيتعذّر تنفيذ الطلب. ويرجع ذلك إلى أنّ النطاق الذي يعرض الصفحة على متصفّحك ليس هو نفسه النطاق الذي يعرض واجهة برمجة التطبيقات Twitter API. تقدّم مشاركة الموارد المتعدّدة المصادر (CORS) حلاً لهذه المشكلة من خلال السماح للخوادم "بالموافقة" على مشاركة الموارد المتعدّدة المصادر إذا أرادت ذلك.

فيديو: شاهِد فيديو قصيرًا للتعرّف على كيفية تفعيل CORS على خادم وكيل لواجهة برمجة التطبيقات.

حالة الاستخدام النموذجية لـ CORS

يستدعي رمز JQuery التالي خدمة مستهدَفة وهمية. إذا تم تنفيذها من داخل سياق متصفّح (صفحة ويب)، ستتعذّر المكالمة بسبب سياسة المصدر الأوحد:

<script>
var url = "http://service.example.com";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This is where we end up!
            }
    });
  });
});
</script>

أحد الحلول لهذه المشكلة هو إنشاء خادم وكيل لواجهة برمجة التطبيقات في Apigee يطلب بيانات من واجهة برمجة التطبيقات الخاصة بالخدمة في الخلفية. تذكَّر أنّ Edge يقع بين العميل (المتصفّح في هذه الحالة) وواجهة برمجة التطبيقات الخلفية (الخدمة). بما أنّ خادم وكيل واجهة برمجة التطبيقات يتم تنفيذه على الخادم وليس في المتصفّح، يمكنه استدعاء الخدمة بنجاح. بعد ذلك، ما عليك سوى إرفاق عناوين CORS باستجابة TargetEndpoint. طالما أنّ المتصفّح يتيح مشاركة الموارد المتعدّدة المصادر (CORS)، تشير هذه العناوين إلى المتصفّح بأنّه لا بأس من "تخفيف" سياسة المصدر الأوحد، ما يسمح بنجاح طلب بيانات من واجهة برمجة التطبيقات المتعدّدة المصادر.

بعد إنشاء الخادم الوكيل الذي يتيح مشاركة الموارد من مصادر مختلفة (CORS)، يمكنك استدعاء عنوان URL الخاص بالخادم الوكيل لواجهة برمجة التطبيقات بدلاً من خدمة الخلفية في الرمز البرمجي من جهة العميل. على سبيل المثال:

<script>
var url = "http://myorg-test.apigee.net/v1/example";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This time, we do not end up here!
            }
    });
  });
});
</script>

ربط سياسة Add CORS بخادم وكيل جديد لواجهة برمجة التطبيقات

يمكنك إضافة إمكانية استخدام CORS إلى خادم وكيل لواجهة برمجة التطبيقات من خلال إرفاق سياسة "إضافة CORS" بخادم وكيل لواجهة برمجة التطبيقات عند إنشائه. لإضافة هذه السياسة، ضَع علامة في مربّع الاختيار إضافة عناوين CORS في صفحة "الأمان" ضمن معالج "إنشاء خادم وكيل".

عند وضع علامة في مربّع الاختيار هذا، تتم إضافة سياسة باسم "إضافة CORS" تلقائيًا إلى النظام ويتم ربطها بمرحلة ما قبل التدفق لاستجابة TargetEndpoint، كما هو موضّح في الشكل التالي:

تمت إضافة سياسة CORS إلى المتصفّح ضمن &quot;السياسات&quot; وإرفاقها بمسار العمل المسبق لاستجابة TargetEndpoint في اللوحة اليمنى

يتم تنفيذ سياسة "إضافة CORS" كـ سياسة AssignMessage، والتي تضيف العناوين المناسبة إلى الاستجابة. بشكل أساسي، تتيح العناوين للمتصفّح معرفة المصادر التي سيشارك معها موارده، والطرق التي يقبلها، وما إلى ذلك. يمكنك قراءة المزيد عن رؤوس CORS هذه في اقتراح مشاركة المراجع مع نطاقات خارجية من W3C.

عليك تعديل السياسة على النحو التالي:

  • أضِف العنوانَين content-type وauthorization (المطلوبَين لتفعيل المصادقة الأساسية أو OAuth2) إلى العنوان Access-Control-Allow-Headers، كما هو موضّح في مقتطف الرمز البرمجي أدناه.
  • بالنسبة إلى مصادقة OAuth2، قد تحتاج إلى اتّخاذ خطوات لتصحيح السلوك غير المتوافق مع RFC.
  • ننصحك باستخدام <Set> لضبط عناوين CORS بدلاً من <Add>، كما هو موضّح في المقتطف أدناه. عند استخدام <Add>، إذا كان العنوان Access-Control-Allow-Origin متوفّرًا، ستتلقّى رسالة الخطأ التالية:

    The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

    لمزيد من المعلومات، يُرجى الاطّلاع على خطأ CORS : يحتوي العنوان على قيم متعدّدة "*, *"، ولكن يُسمح بقيمة واحدة فقط.

<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Set>
        <Headers>
            <Header name="Access-Control-Allow-Origin">{request.header.origin}</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, content-type, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

إضافة عناوين CORS إلى خادم وكيل حالي

عليك إنشاء سياسة "تعيين رسالة" جديدة يدويًا ونسخ الرمز الخاص بسياسة "إضافة CORS" المدرَجة في القسم السابق ولصقه فيها. بعد ذلك، أرفِق السياسة بتدفق ما قبل الطلب الخاص بنقطة نهاية TargetEndpoint لخادم وكيل واجهة برمجة التطبيقات. يمكنك تعديل قيم العناوين حسب الحاجة. لمزيد من المعلومات حول إنشاء السياسات وإرفاقها، يُرجى الاطّلاع على ما هي السياسة؟.

التعامل مع طلبات CORS المبدئية

يشير الطلب المبدئي لبروتوكول CORS إلى إرسال طلب إلى خادم للتحقّق مما إذا كان يتيح استخدام CORS. تتضمّن الردود النموذجية على الطلبات المبدئية المصدر الذي سيقبل الخادم طلبات CORS منه، وقائمة بطُرق HTTP المتوافقة مع طلبات CORS، والعناوين التي يمكن استخدامها كجزء من طلب المورد، والوقت الأقصى الذي سيتم فيه تخزين الردود على الطلبات المبدئية مؤقتًا، وغير ذلك. إذا لم تُشر الخدمة إلى إتاحة مشاركة الموارد المشتركة المنشأ (CORS) أو لم تكن تريد قبول الطلبات متعدّدة المصادر من مصدر العميل، سيتم فرض سياسة متعدّدة المصادر للمتصفح، وستفشل أي طلبات مشتركة النطاق يتم إرسالها من العميل للتفاعل مع الموارد المستضافة على هذا الخادم.

عادةً، يتم إرسال طلبات CORS المبدئية باستخدام طريقة HTTP OPTIONS. عندما يتلقّى خادم يتيح بروتوكول مشاركة الموارد المشتركة المنشأ (CORS) طلب OPTIONS، يعرض مجموعة من عناوين CORS للعميل تشير إلى مستوى إتاحة CORS. نتيجةً لعملية المصافحة هذه، يعرف العميل ما يُسمح له بطلبه من النطاق غير المصدر.

لمزيد من المعلومات عن طلبات التحقّق المسبق، يُرجى الرجوع إلى اقتراح W3C بشأن مشاركة الموارد بين المصادر المختلفة. بالإضافة إلى ذلك، هناك العديد من المدوّنات والمقالات حول CORS التي يمكنك الرجوع إليها.

لا تتضمّن Apigee حلاً للطلب المبدئي لبروتوكول مشاركة الموارد المشتركة المنشأ (CORS) بشكلٍ جاهز، ولكن يمكن تنفيذه كما هو موضّح في هذا القسم. والهدف من ذلك هو أن يقيّم الخادم الوكيل طلب OPTIONS في مسار مشروط. يمكن للخادم الوكيل بعد ذلك إرسال ردّ مناسب إلى العميل.

دعونا نلقي نظرة على نموذج لسير العمل، ثم نناقش الأجزاء التي تتعامل مع طلب التحقّق المسبق:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Response>
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
    </Flows>

    <PreFlow name="PreFlow">
        <Request/>
        <Response/>

    </PreFlow>
    <HTTPProxyConnection>
        <BasePath>/v1/cnc</BasePath>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

في ما يلي الأجزاء الرئيسية من ProxyEndpoint:

  • يتم إنشاء RouteRule لهدف NULL مع شرط لطلب OPTIONS. يُرجى العِلم أنّه لم يتم تحديد أي TargetEndpoint. في حال تلقّي طلب OPTIONS وكانت عناوين الطلب Origin وAccess-Control-Request-Method غير فارغة، يعرض الخادم الوكيل على الفور عناوين CORS في ردّ على العميل (متجاوزًا الهدف التلقائي الفعلي "للخلفية"). للحصول على تفاصيل حول شروط التدفق وRouteRule، يُرجى الاطّلاع على الشروط التي تتضمّن متغيرات التدفق.

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
  • يتم إنشاء مسار OptionsPreFlight يضيف سياسة مشاركة الموارد المتعددة المصادر (CORS)، والتي تحتوي على عناوين CORS، إلى المسار في حال تلقّي طلب OPTIONS وعدم احتواء عناوين الطلب Origin وAccess-Control-Request-Method على قيمة فارغة.

     <Flow name="OptionsPreFlight">
                <Request/>
                <Response>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Response>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>

استخدام نموذج حلّ CORS

يتوفّر حلّ CORS نموذجي، تم تنفيذه كتدفّق مشترك، على GitHub. استورِد حِزمة التدفق المشترَك إلى بيئتك وأرفِقها باستخدام خطافات التدفق أو مباشرةً بتدفقات خادم وكيل واجهة برمجة التطبيقات. للحصول على التفاصيل، راجِع ملف CORS-Shared-FLow README المتوفّر مع النموذج.