افزودن پشتیبانی CORS به پروکسی API

شما در حال مشاهده مستندات Apigee Edge هستید.
به مستندات Apigee X مراجعه کنید .
اطلاعات

CORS (اشتراک‌گذاری منابع بین‌منبعی) یک مکانیزم استاندارد است که به فراخوانی‌های جاوا اسکریپت XMLHttpRequest (XHR) که در یک صفحه وب اجرا می‌شوند، اجازه می‌دهد تا با منابع دامنه‌های غیرمبدأی تعامل داشته باشند. CORS یک راه‌حل رایج برای « سیاست مبدا یکسان » است که توسط همه مرورگرها اجرا می‌شود. به عنوان مثال، اگر از طریق اجرای کد جاوا اسکریپت در مرورگر خود، یک فراخوانی XHR به API توییتر انجام دهید، فراخوانی با شکست مواجه خواهد شد. دلیل این امر این است که دامنه‌ای که صفحه را به مرورگر شما ارائه می‌دهد، همان دامنه‌ای نیست که API توییتر را ارائه می‌دهد. CORS با اجازه دادن به سرورها برای «انتخاب» در صورت تمایل به اشتراک‌گذاری منابع بین‌منبعی، راه‌حلی برای این مشکل ارائه می‌دهد.

ویدیو: برای یادگیری نحوه فعال کردن CORS روی پروکسی API، یک ویدیوی کوتاه تماشا کنید.

مورد استفاده معمول برای CORS

کد جی‌کوئری زیر یک سرویس هدف فرضی را فراخوانی می‌کند. اگر از درون یک مرورگر (یک صفحه وب) اجرا شود، به دلیل سیاست مبدا یکسان، فراخوانی با شکست مواجه خواهد شد:

<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>

یک راه حل برای این مشکل، ایجاد یک پروکسی API از Apigee است که API سرویس را در backend فراخوانی می‌کند. به یاد داشته باشید که Edge بین کلاینت (در این مورد یک مرورگر) و API backend (سرویس) قرار می‌گیرد. از آنجا که پروکسی API روی سرور اجرا می‌شود، نه در مرورگر، می‌تواند سرویس را با موفقیت فراخوانی کند. سپس، تنها کاری که باید انجام دهید این است که هدرهای CORS را به پاسخ TargetEndpoint متصل کنید. تا زمانی که مرورگر از CORS پشتیبانی می‌کند، این هدرها به مرورگر سیگنال می‌دهند که اشکالی ندارد که سیاست same-origin خود را "رها" کند و به فراخوانی cross-origin API اجازه دهد تا با موفقیت انجام شود.

پس از ایجاد پروکسی با پشتیبانی CORS، می‌توانید به جای سرویس backend در کد سمت کلاینت خود، آدرس پروکسی API را فراخوانی کنید. برای مثال:

<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 به یک پروکسی API جدید

شما می‌توانید با پیوست کردن یک سیاست "افزودن CORS" به پروکسی API هنگام ایجاد آن، پشتیبانی CORS را به آن اضافه کنید. برای افزودن این سیاست، کادر انتخاب Add CORS headers را در صفحه امنیت از ویزارد ساخت پروکسی انتخاب کنید.

وقتی این کادر انتخاب را انتخاب می‌کنید، یک سیاست به نام Add CORS به طور خودکار به سیستم اضافه می‌شود و به پیش‌جریان پاسخ TargetEndpoint متصل می‌شود، همانطور که در شکل زیر نشان داده شده است:

سیاست CORS را که به ناویگاتور در قسمت سیاست‌ها اضافه شده و به پیش‌جریان پاسخ TargetEndpoint در پنل سمت راست متصل شده است، اضافه کنید.

سیاست Add CORS به عنوان یک سیاست AssignMessage پیاده‌سازی شده است که هدرهای مناسب را به پاسخ اضافه می‌کند. اساساً، هدرها به مرورگر اطلاع می‌دهند که منابع خود را با کدام مبدأها به اشتراک می‌گذارد، کدام روش‌ها را می‌پذیرد و غیره. می‌توانید اطلاعات بیشتر در مورد این هدرهای CORS را در توصیه‌نامه W3C در مورد به اشتراک‌گذاری منابع Cross-Origin مطالعه کنید.

شما باید سیاست را به صورت زیر تغییر دهید:

  • هدرهای 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 به یک پروکسی موجود

شما باید به صورت دستی یک سیاست جدید Assign Message ایجاد کنید و کد مربوط به سیاست Add CORS که در بخش قبلی ذکر شده است را در آن کپی کنید. سپس، این سیاست را به پیش‌جریان پاسخ TargetEndpoint پروکسی API پیوست کنید. می‌توانید مقادیر هدر را در صورت نیاز تغییر دهید. برای اطلاعات بیشتر در مورد ایجاد و پیوست کردن سیاست‌ها، به بخش «سیاست چیست؟ » مراجعه کنید.

رسیدگی به درخواست‌های پیش از پرواز CORS

پیش‌پرواز CORS به ارسال درخواست به یک سرور برای تأیید پشتیبانی آن از CORS اشاره دارد. پاسخ‌های معمول پیش‌پرواز شامل مواردی مانند مبدأهایی است که سرور درخواست‌های CORS را از آنها می‌پذیرد، فهرستی از روش‌های HTTP که برای درخواست‌های CORS پشتیبانی می‌شوند، هدرهایی که می‌توانند به عنوان بخشی از درخواست منبع استفاده شوند، حداکثر زمان ذخیره پاسخ پیش‌پرواز و موارد دیگر. اگر سرویس پشتیبانی CORS را نشان ندهد یا نخواهد درخواست‌های بین‌دامنه‌ای را از مبدأ کلاینت بپذیرد، سیاست بین‌دامنه‌ای مرورگر اجرا خواهد شد و هرگونه درخواست بین‌دامنه‌ای که از کلاینت برای تعامل با منابع میزبانی شده در آن سرور ارسال می‌شود، با شکست مواجه خواهد شد.

معمولاً درخواست‌های پیش از ارسال CORS با روش HTTP OPTIONS انجام می‌شوند. وقتی سروری که از CORS پشتیبانی می‌کند، درخواست OPTIONS دریافت می‌کند، مجموعه‌ای از هدرهای CORS را به کلاینت برمی‌گرداند که سطح پشتیبانی CORS آن را نشان می‌دهد. در نتیجه این handshake، کلاینت می‌داند که مجاز به درخواست چه چیزی از دامنه غیر مبدا است.

برای اطلاعات بیشتر در مورد پیش از شروع، به توصیه W3C در مورد به اشتراک گذاری منابع بین مبدا (Cross-Origin Resource Sharing) مراجعه کنید. علاوه بر این، وبلاگ‌ها و مقالات متعددی در مورد 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 با یک شرط برای درخواست OPTIONS به یک هدف NULL ایجاد می‌شود. توجه داشته باشید که هیچ TargetEndpoint مشخص نشده است. اگر درخواست OPTIONS دریافت شود و هدرهای درخواست Origin و Access-Control-Request-Method تهی نباشند، پروکسی بلافاصله هدرهای CORS را در پاسخ به کلاینت برمی‌گرداند (با دور زدن هدف پیش‌فرض "backend"). برای جزئیات بیشتر در مورد شرایط جریان و RouteRule، به Conditions with flow variables مراجعه کنید.

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
  • یک جریان OptionsPreFlight ایجاد می‌شود که در صورت دریافت درخواست OPTIONS و عدم تهی بودن سرآیندهای درخواست Origin و Access-Control-Request-Method، یک سیاست Add CORS، شامل سرآیندهای CORS، را به جریان اضافه می‌کند.

     <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 موجود است. بسته جریان مشترک را به محیط خود وارد کنید و آن را با استفاده از قلاب‌های جریان یا مستقیماً به جریان‌های پروکسی API متصل کنید. برای جزئیات بیشتر، به فایل README CORS-Shared-FLow که همراه با نمونه ارائه شده است، مراجعه کنید.