אתם צופים במסמכי התיעוד של Apigee Edge.
כדאי לעיין במסמכי התיעוד של Apigee X. מידע
שיתוף משאבים בין מקורות (CORS) הוא מנגנון סטנדרטי שמאפשר לקריאות JavaScript XMLHttpRequest (XHR) שמופעלות בדף אינטרנט ליצור אינטראקציה עם משאבים מדומיינים שאינם מקור. CORS הוא פתרון נפוץ לבעיה של מדיניות same-origin שנאכפת על ידי כל הדפדפנים. לדוגמה, אם שולחים קריאת XHR ל-Twitter API מקוד JavaScript שמופעל בדפדפן, הקריאה תיכשל. הסיבה לכך היא שהדומיין שממנו הדף מוצג בדפדפן שלכם לא זהה לדומיין שממנו מוצג Twitter API. 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 של ה-Backend (השירות). מכיוון ש-proxy ל-API מופעל בשרת ולא בדפדפן, הוא יכול לקרוא לשירות בהצלחה. לאחר מכן, כל מה שצריך לעשות הוא לצרף כותרות CORS לתגובה של TargetEndpoint. כל עוד הדפדפן תומך ב-CORS, הכותרות האלה מאותתות לדפדפן שמותר לו להקל על מדיניות המקורות הזהים, וכך לאפשר לקריאה ל-API ממקורות שונים להצליח.
אחרי שיוצרים את ה-proxy עם תמיכה ב-CORS, אפשר לקרוא לכתובת ה-URL של ה-proxy ל-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 לשרת proxy חדש של API
אפשר להוסיף תמיכה ב-CORS ל-proxy ל-API על ידי צירוף מדיניות 'הוספת CORS' ל-proxy ל-API כשיוצרים אותו. כדי להוסיף את המדיניות הזו, מסמנים את התיבה Add CORS headers (הוספת כותרות CORS) בדף Security (אבטחה) באשף Build a Proxy (יצירת שרת proxy).
כשמסמנים את התיבה הזו, מדיניות בשם Add CORS מתווספת אוטומטית למערכת ומצורפת ל-TargetEndpoint response preflow, כמו שמוצג באיור הבא:

המדיניות Add CORS policy מיושמת כמדיניות 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 Error : header contains multiple values '*, *', but only one is allowed.
<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 קיים
צריך ליצור באופן ידני מדיניות חדשה של הקצאת הודעות ולהעתיק אליה את הקוד של מדיניות Add CORS שמופיע בקטע הקודם. לאחר מכן, מצרפים את המדיניות ל-PreFlow של התגובה של TargetEndpoint של proxy ל-API. אפשר לשנות את ערכי הכותרת לפי הצורך. מידע נוסף על יצירה וצירוף של מדיניות זמין במאמר מהי מדיניות?
טיפול בבקשות קדם-הפעלה של CORS
קדם-הפעלה של CORS מתייחסת לשליחת בקשה לשרת כדי לוודא שהוא תומך ב-CORS. תשובות אופייניות לבקשות קדם-הפעלה כוללות את המקורות שהשרת יקבל מהם בקשות CORS, רשימה של שיטות HTTP שנתמכות בבקשות CORS, כותרות שאפשר להשתמש בהן כחלק מבקשת המשאב, הזמן המקסימלי שבו תשובת קדם-ההפעלה תישמר במטמון ועוד. אם השירות לא מציין תמיכה ב-CORS או לא רוצה לקבל בקשות ממקורות שונים מהמקור של הלקוח, מדיניות המקורות השונים של הדפדפן תיאכף וכל הבקשות בין דומיינים שיישלחו מהלקוח כדי ליצור אינטראקציה עם משאבים שמארח השרת הזה ייכשלו.
בדרך כלל, בקשות קדם-הפעלה של CORS מבוצעות באמצעות שיטת HTTP OPTIONS. כששרת שתומך ב-CORS מקבל בקשת OPTIONS, הוא מחזיר ללקוח קבוצה של כותרות CORS שמציינות את רמת התמיכה שלו ב-CORS. כתוצאה מהלחיצת יד הזו, הלקוח יודע מה מותר לו לבקש מהדומיין שאינו המקור.
מידע נוסף על בקשות Preflight מופיע בהמלצה של W3C בנושא שיתוף משאבים בין מקורות (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 הם:
- נוצר RouteRule ליעד NULL עם תנאי לבקשת OPTIONS. שימו לב:
לא צוין TargetEndpoint. אם מתקבלת בקשת OPTIONS וכותרות הבקשה Origin ו-Access-Control-Request-Method אינן null, ה-proxy מחזיר מיד את כותרות ה-CORS בתגובה ללקוח (תוך דילוג על יעד ברירת המחדל בפועל של ה-backend).
פרטים על תנאי זרימה ו-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 אינן null.
<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. מייבאים את חבילת התהליך המשותף לסביבה ומצרפים אותה באמצעות ווים של תהליך או ישירות למסלולים של proxy ל-API. פרטים נוספים מופיעים בקובץ CORS-Shared-FLow README שמצורף לדוגמה.