כיצד להימנע משגיאות CORS בבקשות API

בקשות API נכשלות, והמוצר מאבד משתמשים — אנו מגדירים CORS באופן מלא ומחזירים חילופי נתונים יציבים בין שירותים. המהנדסים שלנו מטפלים בגורם השורש ולא בסימפטום: השחרור מפסיק להיות תלוי בשגיאות אינטגרציה אקראיות.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
כיצד להימנע משגיאות CORS בבקשות API
פשוט
~2-3 שעות
שאלות נפוצות

מדוע בקשות API נכשלות בגלל CORS ואיך זה שובר את המוצר

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

המשתמש חושב שהשירות שבור, למרות שה-backend עבד כראוי והחזיר נתונים — הדפדפן דחה אותם בשלב בדיקת מדיניות המקור.

כשל טיפוסי שני — בקשה מקדימה שנדחתה. לפני בקשה "מורכבת" ל-API, הדפדפן שואל את השרת בנפרד על הרשאה, ואם בתגובה אין את הכותרות הנדרשות, הדבר לא מגיע כלל לקריאה עצמה.

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

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

מה נותנת הגדרה נכונה של CORS: האפקט במספרים

הגדרה נכונה של CORS מסירה סוג שלם של כשלים, שאחרת צץ כבר בפרודקשן: הדפדפן חוסם את הבקשה, הפרונטנד מקבל תגובה ריקה במקום נתונים, ובלוגים של הבקנד דווקא נקי — הבקשה פשוט לא מגיעה לשרת.

אבחון של תקלה כזו אורך שעות, כי הסימפטום נראה רק בקונסולת הדפדפן של משתמש מסוים, ולא במוניטורינג של ה-API. כשהמדיניות מוגדרת במפורש — ברשימת מקורות, מתודות וכותרים מותרים — התרחיש הזה מפסיק להתקיים כסוג.

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

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

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

בדיוק במפגש של האפקטים האלה — פחות תקלות, פחות עבודה ידנית, גרסאות יציבות יותר — ניכר שהגדרת CORS היא לא פורמליות, אלא חלק מעמידות המוצר.

גישות להגדרת CORS: השוואת אפשרויות

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

אפשרות מתי מתאימה מגבלות
כותרות הרשאה בשרת ה-API Backend משלכם, רשימה מוגבלת של דומיינים של ה-Frontend, נדרשים cookie והרשאה יש לתחזק את רשימת הדומיינים ידנית; עם כמה סביבות קל לקבל חוסר סנכרון; שגיאה בכותרות נראית רק בדפדפן
פרוקסי דרך הדומיין שלכם API של צד שלישי בלי גישה להגדרות שלו, עקיפה מהירה של מגבלות הדפדפן הפרוקסי הופך לנקודת כשל ודורש משאבים; ההשהיה גדלה; יש לפתור בנפרד הרשאה ומגבלות
API Gateway לפני השירותים כמה שירותים, כללי גישה אחידים, נדרשת מדיניות ריכוזית דורש תשתית ותחזוקה; עבור שירות אחד מיותר; יש לבדוק את כללי ה-Gateway בנפרד מהקוד
ניהול כותרות ידני בקוד אב-טיפוס, כלי פנימי, בקשה חד-פעמית שכפול לוגיקה בכל שירות; בעת ריפקטורינג הכללים הולכים לאיבוד; לא מתרחב לצוות

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

ל-API Gateway יש смысל כאשר יש יותר משירות אחד: כללי הגישה מתוארים פעם אחת ומיושמים על כולם, במקום להתפזר בין קונפיגורציות. עריכה ידנית של כותרות מתאימה רק כפתרון זמני — היא לא שורדת את גדילת הצוות ואת הריפקטורינג הראשון.

בפועל הבחירה תלויה במי שייך ה-API ובכמה סביבות יש לתמוך. ננתח את סכמת הבקשות שלכם — נחזור עם הערכה איזו אפשרות תסגור את המשימה בלי שכבה מיותרת.

שלבי יישום: מביקורת בקשות ועד מסירת נהלים

הגדרת CORS אינה תיקון אחד בקונפיגורציית השרת, אלא רצף של שלבים, שכל אחד מהם נשען על הקודם. אם מדלגים על הביקורת ומציבים כותרות מיד, חלק מהבקשות ייכשלו, וחלק יישארו פתוחות לרווחה יותר מהנדרש. לכן אנו עובדים בשלבים עם בדיקה בכל אחד מהם.

  1. ביקורת בקשות. אוספים את כל המקורות שמהם הפרונטאנד פונה ל-API: דומיינים, תת-דומיינים, כתובות מקומיות של מפתחים, ווידג'טים חיצוניים. מתעדים מתודות, כותרות ותרחישים עם פרטי זיהוי — דווקא הם נשברים לרוב במדיניות שגויה.
  2. תכנון המדיניות. קובעים אילו מקורות אנו מתירים במפורש, אילו מתודות וכותרות אנו מאשרים, האם נדרשים פרטי זיהוי וכיצד אנו מטפלים בבקשות מקדימות. במקום תבנית "להתיר לכולם" מקבלים רשימת חוקים לתרחישים אמיתיים.
  3. הגדרה. מעבירים את החוקים לשרת ולשכבת הביניים: כותרות תגובה, טיפול בבקשות מקדימות, מטמון הרשאות. בנפרד בודקים שהמדיניות אינה מתנגשת עם פרוקסי ומאזן עומסים.
  4. בדיקת תרחישים. מריצים שרשראות אמיתיות: התחברות, העלאת קבצים, בקשות עם פרטי זיהוי, פניות מדומיינים חיצוניים. בודקים שהמותר עובר, והאסור נדחה עם שגיאה מובנת.
  5. תיעוד. מתארים את החוקים הפעילים, את הסיבות לכל הרשאה ואת סדר הוספת מקור חדש — כדי שהתיקון הבא לא יהפוך לארכיאולוגיה.
  6. מסירה. מוסרים את הנהלים לצוות, מתעדים אחראים ונקודות בקרה. המדיניות הופכת לחלק מהתהליך, ולא לתיקון חד-פעמי.

סדר כזה מסיר סוג של שגיאות שבהן הדפדפן חוסם בקשה, והסיבה אינה ברורה. תארו את המשימה — נחזור עם הערכה ותוכנית לפי שלבים.

מה הלקוח מקבל לידיו: קונפיגורציות ותקנונים

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

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

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

מקרה בוחן: כיצד סילקנו כשלים בבקשות והאצנו את מחזור השחרור

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

מה מצאנו

הסיבה התבררה כמשולבת. פרוקסי הפוך החזיר כותרות שונות לבקשות עם Origin ובלעדיו, ובקשת ה-OPTIONS המקדימה בחלק מהמסלולים הגיעה לאפליקציה במקום לפרוקסי והחזירה הפניה מחדש — הדפדפן אינו מקבל תשובה כזו וחוסם את הבקשה הראשית.

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

מה שינינו

הוצאנו את המדיניות אל תצורת הפרוקסי: רשימת מקורות אחידה, טיפול מפורש ב-OPTIONS לפני ההגעה לאפליקציה, סט תקין של Access-Control-Allow-Methods ו-Access-Control-Allow-Headers בהתאם לשיטות ולכותרות שבשימוש בפועל.

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

מדדים לפני ואחרי

מדד לפני אחרי
שיעור הבקשות עם שגיאת מדיניות 6-9% בשעות שיא 0
פניות לתמיכה בנושא «הכניסה לא עובדת» 40+ בשבוע בודדות
זמן להוספת תת-דומיין חדש 2-3 ימי עריכות ושחרור עריכת תצורה בדקות
שחרור שינויים ב-API בחשש, נקודתית מחזור שגרתי

אפקט נפרד — צפיות בשחרור. בעבר כל עריכה של דומיינים או כותרות גררה אחריה שחרור אפליקציה ובדיקה ידנית, כעת זהו שינוי תצורה שעובר סקירה ומתבטל בשורה אחת. הצוות הפסיק לחשוש לגעת באינטגרציות.

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

במה שונה הגדרת CORS בשרת ובשער?

בשרת, המדיניות נקבעת על ידי היישום עצמו: הכותרות Access-Control-Allow-Origin, Allow-Methods, Allow-Headers נוצרות ב-handler או ב-middleware ונשלחות בכל תגובה.

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

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

השער מוציא את אותה מדיניות לרמה שלפני היישומים. הכללים מתוארים באופן הצהרתי ומיושמים על כל הנתיבים בבת אחת, באופן אחיד, ללא תלות במה שהשירות כתוב. בקשת ה-preflight מסוג OPTIONS מטופלת בכניסה ואינה מגיעה ליישום — ה-backend אינו מבזבז משאבים על קריאות שירות.

הצד השני של המטבע: השער רואה רק את קווי המתאר החיצוניים של הבקשה ואינו מכיר את הלוגיקה הפנימית, ולכן כללים עדינים כמו "מקור A — לקריאה בלבד, מקור B — לכתיבה בלבד" מתבטאים בו בצורה גסה יותר.

ההבדל המרכזי הוא בנקודת היישום של המדיניות. בשרת היא חלק מהיישום ומשתנה יחד עם ה-release; בשער זוהי קונפיגורציה של תשתית, שמתקנים בנפרד מהקוד ומפיצים באופן מרוכז.

מכאן גם מחיר שונה של טעות: כותרת שגויה בקוד מתוקנת ב-deploy חדש של השירות, כלל שגוי בשער — בתיקון קונפיגורציה ללא בנייה מחדש של היישומים.

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

ספקות טכניים נפוצים בהגדרת CORS

לפני שמשנים כותרות תגובה, כדאי להבין: CORS אינו "הגדרה בשרת", אלא חוזה מתואם בין מקור הבקשה ל-API. רוב הספקות מתעוררים במקום שבו ה-frontend וה-backend מתקנים את חלקיהם בנפרד ובודקים את התוצאה רק בדפדפן — לפי הופעת השגיאה בקונסול.

הפתרון כבר פרוס, אבל הבקשות עדיין נכשלות — מה לבדוק ראשון?

להסתכל על בקשת ה-preflight: אם היא יוצאת וחוזרת בלי הכותרות הנדרשות, הבקשה הראשית כלל לא מגיעה ל-API. לאחר מכן — סדר הטיפול: מדיניות ברמת ה-reverse proxy עשויה לדרוס את מה שהיישום מציב.

והמקור השלישי הנפוץ — מטמון: הדפדפן שומר את תוצאת בקשת ה-preflight, ולכן השינויים אינם נראים עד לאיפוס. בודקים את השרשרת כולה, ולא רק את קוד היישום.

איך להימנע מהתנגשויות בין ה-proxy, היישום והשירות החיצוני?

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

איך לבדוק שההגדרה אכן עובדת?

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

מה לעשות עם אינטגרציות שכבר עובדות בעת שינוי המדיניות?

להכניס שינויים בהדרגה: תחילה מרחיבים את הרשימה, עוקבים אחר הפניות, ורק אחר כך מסירים את המיותר. לוגים של בקשות עם מקורות שנדחו נותנים תמונה מדויקת של מי עוד פונה ל-API. כך הבנייה מחדש עוברת בלי כשלים פתאומיים אצל צוותים סמוכים.

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

נדון במשימה שלך ונחזור עם הערכה ותוכנית

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

תארו את המשימה בצורה חופשית — זה מספיק כדי להתחיל:

  • אילו דומיינים ותת-דומיינים פונים ל-API שלכם (frontend, אפליקציית מובייל, אינטגרציות שותפים);
  • אילו מתודות נדרשות: רק קריאה או גם כתיבה, מחיקה, בקשות מקדימות;
  • האם מועברים פרטי זיהוי — cookie, טוקנים בכותרים, סשנים;
  • היכן כרגע נוצרת השגיאה: בדפדפן, בלוגים של השרת, רק אצל חלק מהמשתמשים;
  • איזה סטאק יש ב-frontend וב-backend, מי אחראי על הגדרות השרת וה-reverse proxy;
  • האם יש מגבלות: דרישות אבטחה, תקנות, איסור על עריכות בשירות של מישהו אחר.

נלמד את ההקשר, נשחזר את ההתנהגות על סמך סכימת הבקשות שלכם ונציע פתרון — עם תוכנית עבודה, לוחות זמנים ומה נדרש מצדכם. אם המשימה נפתרת בתיקון נקודתי של המדיניות, נגיד זאת ישירות; אם נדרשת עיבוד מחדש של סכימת הגישה, גם נסמן זאת בכנות, בלי לכפות נפח עבודה מיותר.

נדון במשימה — כתבו בערוץ הנוח לכם, צרפו דוגמאות של בקשות ותגובות, אם יש. נחזור עם הערכה ותוכנית.

הכישורים שלנו:

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1394
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1369
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1142
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1153
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1232
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    642