הוספה של תמיכת CORS לשרת proxy של API

מוצג המסמך של Apigee Edge.
עוברים אל מסמכי תיעוד של Apigee X.
מידע

CORS (שיתוף משאבים בין מקורות) הוא מנגנון סטנדרטי שמאפשר JavaScript קריאות XMLHttpRequest (XHR) שבוצעו בדף אינטרנט כדי לקיים אינטראקציה עם משאבים שאינם ממקור דומיינים. CORS הוא פתרון מקובל למדיניות המקור הזהה. שנאכפת על ידי כל הדפדפנים. לדוגמה, אם מבצעים קריאת XHR ל-API של Twitter מקוד JavaScript מופעל בדפדפן, השיחה תיכשל. הסיבה לכך היא שהדומיין משרת את הדף הדפדפן שלך אינו זהה לדומיין שמציג את ממשק ה-API של Twitter. CORS מספק פתרון את הבעיה הזו באמצעות מתן אפשרות לשרתים 'להביע הסכמה' אם הוא רוצה לספק משאב בין מקורות בשיתוף.

סרטון: כדאי לצפות בסרטון קצר כדי ללמוד איך מפעילים CORS בשרת proxy ל-API.

תרחיש לדוגמה אופייני ל-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>

אחד הפתרון לבעיה הזו הוא ליצור שרת proxy ל-API של Apigee שקורא ל-API של השירות בקצה העורפי. חשוב לזכור ש-Edge נמצא בין הלקוח (במקרה הזה דפדפן) לקצה העורפי API (השירות). מכיוון ששרת ה-Proxy ל-API פועל בשרת ולא בדפדפן, הוא יכול לקרוא לשירות בהצלחה. לאחר מכן, כל מה שצריך לעשות לצרף כותרות CORS לתגובה של TargetEndpoint. כל עוד הדפדפן תומך ב-CORS, הכותרות האלה מסמנות לדפדפן שזה בסדר "להירגע" מדיניות המקור הזהה, שמאפשרת את הקריאה ל-API ממקורות שונים כדי להצליח.

אחרי יצירת שרת ה-Proxy עם תמיכה ב-CORS, אפשר לקרוא לכתובת ה-URL של ה-API proxy במקום לשירות לקצה העורפי בקוד בצד הלקוח. לדוגמה:

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

צירוף של מדיניות CORS ל-API חדש שרת proxy

אפשר להוסיף תמיכה ב-CORS לשרת proxy ל-API על ידי צירוף 'הוספת CORS'. מדיניות לשרת ה-proxy ל-API כשיוצרים אותו. כדי להוסיף את המדיניות הזו, צריך לסמן את התיבה הוספת כותרות CORS את הדף 'אבטחה' באשף Build a Proxy.

כשמסמנים את התיבה הזו, מדיניות בשם 'הוספת CORS' מתווספת באופן אוטומטי למערכת ומצורף לתהליך מראש של תגובת TargetEndpoint, כמו שמוצג באיור הבא:

הוספה של מדיניות CORS שנוספה לכלי הניווט בקטע &#39;כללי מדיניות&#39; ומצורפת לזרימה מראש של תגובת יעד-קצה (TargetEndpoint) בחלונית הימנית

מדיניות הוספת ה-CORS מוטמעת כ-AssignMessage מוסיפה את הכותרות המתאימות לתשובה. בעיקרון, הכותרות מאפשרות לדפדפן לדעת עם אילו מקורות הוא משתף את המשאבים שלו, אילו שיטות היא מקבלת וכו'. מידע נוסף על כותרות CORS האלה זמין המלצה לגבי שיתוף משאבים בין מקורות

צריך לשנות את המדיניות באופן הבא:

  • צריך להוסיף את הכותרות 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 לשרת proxy קיים

עליך ליצור באופן ידני מדיניות חדשה של הקצאת הודעות ולהעתיק את הקוד של הוספת CORS שצוינה בסעיף הקודם. לאחר מכן, מצרפים את המדיניות לתהליך העבודה מראש של התשובה של נקודת הקצה (TargetEndpoint) של שרת ה-proxy ל-API. אפשר לשנות את ערכי הכותרת לפי הצורך. לקבלת מידע נוסף מידע על יצירה וצירוף של כללי מדיניות זמין במאמר מהי מדיניות?

טיפול ב-CORS בקשות קדם-הפעלה

קדם-הפעלה של CORS: שליחת בקשה לשרת כדי לאמת שתומך ב-CORS. תגובות קדם-הפעלה אופייניות כוללות את המקורות שהשרת יקבל CORS בקשות מ-, רשימה של שיטות HTTP שנתמכות בבקשות CORS, כותרות שיכולות להיות כחלק מבקשת המשאב, הזמן המקסימלי של תגובת קדם-הפעלה יישמר במטמון. אחרים. אם השירות לא מציין תמיכה ב-CORS או שהוא לא רוצה לקבל המרות ממקורות שונים של בקשות מהמקור של הלקוח, המדיניות של הדפדפן ממקורות שונים תיאכף וגם כל בקשה בין דומיינים שנשלחה מהלקוח לאינטראקציה עם משאבים שמתארחים בשרת הזה ייכשל.

בדרך כלל, בקשות קדם-הפעלה של CORS מבוצעות עם ה-method HTTP OPTIONS. כאשר שרת עם תמיכה ב-CORS מקבל בקשת OPTIONS, הוא יחזיר קבוצה של כותרות CORS ללקוח לציין את רמת התמיכה ב-CORS. כתוצאה מלחיצת היד הזו, הלקוח יודע מהו מורשה לבקש מדומיין שאינו המקור.

מידע נוסף על קדם-ההפעלה זמין בהמלצה לגבי שיתוף משאבים בין מקורות. יש ב: בנוסף, הוספת בלוגים ומאמרים רבים בנושא CORS, שאפשר להפנות אליהם.

Apigee לא כוללת פתרון קדם-הפעלה של CORS מחוץ לקופסה, אבל ניתן להטמיע, כפי שמתואר בקטע הזה. המטרה היא ששרת ה-Proxy יעריך OPTIONS את הבקשה בתהליך מותנה. לאחר מכן שרת ה-proxy יכול לשלוח תגובה מתאימה חזרה הלקוח.

בואו נבחן תהליך לדוגמה ולאחר מכן נדון בחלקים שמטפלים בבקשת קדם-ההפעלה:

<?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 הזו הם:

  • כלל מסלול נוצר ליעד NULL עם תנאי לבקשת OPTIONS. שימו לב לא צוינה נקודת יעד (TargetEndpoint). אם הבקשה OPTIONS מתקבלת, והמקור וגם כותרות הבקשה Access-Control-Request-Method אינן ריקות, שרת ה-proxy מחזיר מיד את כותרות 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, והמקור כותרות הבקשות 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. מייבאים את חבילת התהליכים המשותפת לסביבה שלכם ומצרפים אותה באמצעות קטעי הוק (hooks) לזרימה או ישירות לתהליכי ה-Proxy ל-API. פרטים נוספים זמינים במאמר סופק עם הדוגמה קובץ CORS-Shared-FLow README.