已更新 1个月前
אתה שולח בקשת fetch. השרת מגיב. ואז הדפדפן שלך זורק את התשובה לפח.
זהו CORS — שיתוף משאבים בין מקורות שונים (Cross-Origin Resource Sharing). והדבר שהופך את התסכול להבנה: השרת כבר עיבד את הבקשה שלך. הוא הריץ את הקוד שלך, נגע במסד הנתונים שלך, החזיר את הנתונים שלך. CORS רק מחליט אם ה-JavaScript שלך יוכל לראות מה קרה.
CORS הוא הדפדפן שמשחק את תפקיד השומר בכניסה, בודק את רשימת האורחים בכל תגובה.
למה הדפדפנים עושים את זה
דמיין שאתה מחובר לחשבון הבנק שלך בכתובת https://mybank.com. הדפדפן שלך מחזיק את ה-cookie של ה-session שלך. עכשיו אתה מבקר ב-https://sketchy-site.com, וקוד JavaScript סמוי מופעל:
ללא CORS, זה עובד. הדפדפן שלך שולח אוטומטית את ה-cookies של הבנק עם הבקשה. ההעברה מתבצעת. התוקף מקבל את הכסף שלך.
CORS מונע זאת על ידי דרישה ש-https://mybank.com יאמר במפורש "כן, אני סומך על בקשות מ-https://sketchy-site.com". מאחר שאף בנק לגיטימי לא יאמר זאת, הדפדפן חוסם את התגובה — וחשוב יותר, חוסם לחלוטין בקשות עם פרטי אישור ללא אישור מראש.
מה מרכיב מקור
מקור הוא שילוב של סכמה, שם המארח ויציאה:
https://example.comו-http://example.com— מקורות שונים (סכמה שונה)https://example.comו-https://api.example.com— מקורות שונים (שם מארח שונה)https://example.com:443ו-https://example.com:8443— מקורות שונים (יציאה שונה)
אותו מקור פירושו שכל שלושת המרכיבים תואמים בדיוק.
הכותרות השולטות בהכל
Access-Control-Allow-Origin
כרטיס הכניסה הבסיסי:
זה אומר: "JavaScript מ-https://app.example.com רשאי לגשת לתגובה זו." כל מקור אחר ייחסם.
התו הכללי מאפשר לכולם:
מתאים לנתונים ציבוריים באמת. מסוכן לכל דבר אחר. וחשוב: תווים כלליים לא עובדים עם פרטי אישור.
Access-Control-Allow-Credentials
כברירת מחדל, בקשות בין מקורות אינן כוללות cookies או כותרות Authorization. כדי לאפשר אותן:
שניהם נדרשים. ושימו לב: אין תו כללי. כאשר פרטי אישור מעורבים, השרת חייב לציין את המקור הספציפי שהוא סומך עליו. זה מכוון. אי אפשר לומר "אני סומך על כולם עם האימות של המשתמשים שלי."
Access-Control-Allow-Methods
אילו שיטות HTTP מותרות:
Access-Control-Allow-Headers
אילו כותרות בקשה מותרות:
כברירת מחדל, רק מספר מועט של כותרות "בטוחות" מותרות. ברגע שאתה מוסיף Authorization או Content-Type: application/json, אתה זקוק לאישור מפורש.
Access-Control-Max-Age
כמה זמן (בשניות) לשמור במטמון את בדיקת ההרשאה:
זה חשוב בגלל בקשות preflight.
Access-Control-Expose-Headers
כברירת מחדל, JavaScript יכול לראות רק מעט כותרות תגובה. כדי לחשוף כותרות מותאמות אישית:
בקשות פשוטות לעומת Preflight
חלק מהבקשות הן "פשוטות" — הדפדפן שולח אותן ישירות ובודק את CORS על התגובה:
- שיטת GET, HEAD, או POST
- רק כותרות סטנדרטיות (Accept, Content-Type עם ערכי טופס, וכו')
- Content-Type מוגבל ל-
application/x-www-form-urlencoded,multipart/form-data, אוtext/plain
כל שאר המקרים מפעיל preflight — בקשת OPTIONS שמבקשת אישור לפני הבקשה האמיתית:
השרת מגיב עם מה שהוא מאפשר:
אם ה-preflight עובר, הדפדפן שולח את הבקשה האמיתית. אם הוא נכשל, הבקשה האמיתית לא מתרחשת כלל.
זו הסיבה ש-Access-Control-Max-Age חשוב — ללא שמירה במטמון, כל קריאת API עם כותרות מותאמות אישית דורשת שני הלוך ושוב.
שגיאות נפוצות ומה הן אומרות
"No 'Access-Control-Allow-Origin' header is present"
השרת לא כלל כותרות CORS בכלל. CORS לא מוגדר, או שהוא אינו מוגדר עבור המקור שלך.
"The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*' when the request's credentials mode is 'include'"
אתה שולח פרטי אישור (cookies, Authorization) אבל השרת החזיר *. הוא חייב להחזיר את המקור המדויק שלך.
"Method PUT is not allowed by Access-Control-Allow-Methods"
תגובת ה-preflight לא כללה PUT. הוסף אותו לשיטות המותרות.
"Request header field authorization is not allowed by Access-Control-Allow-Headers"
תגובת ה-preflight לא אפשרה את כותרת Authorization. הוסף אותה.
ניפוי שגיאות
פתח את DevTools. שתי לשוניות חשובות:
Console: מציגה את שגיאת CORS עם פרטים על מה שנכשל.
Network: מציגה את הבקשות בפועל. חפש:
- את ה-OPTIONS preflight (אם קיים)
- את כותרות התגובה (או היעדרן)
- האם הבקשה נחסמה לעומת האם התגובה נחסמה
זכור: אם אתה רואה את הבקשה בלשונית Network עם תגובה, השרת עיבד אותה. CORS רק מנע מה-JavaScript שלך לקרוא את התוצאה.
הגדרת שרת
Express/Node.js:
Nginx:
הוראת always מבטיחה שהכותרות מופיעות גם בתגובות שגיאה — אחרת שגיאת 500 עלולה להיות חסרת כותרות CORS, מה שמקשה על ניפוי שגיאות.
היבטי אבטחה
CORS הוא אבטחת דפדפן, לא אבטחת שרת. כל מי שמשתמש ב-curl, Postman, או לקוח מותאם אישית עוקף את CORS לחלוטין. הוא מגן על משתמשים מאתרים זדוניים, לא על ה-API שלך מגורמים זדוניים.
לעולם אל תחזיר את כותרת Origin באופן עיוור:
שמור על רשימת היתרים:
פרטי אישור דורשים זהירות מיוחדת. Access-Control-Allow-Credentials: true פירושו "למקור הזה מותר לשלוח בקשות מאומתות בשם המשתמש." הענק הרשאה זו רק למקורות שאתה שולט בהם לחלוטין.
תווים כלליים הם לנתונים ציבוריים בלבד. אם ה-API שלך דורש אימות, * הוא שגוי.
המודל המנטלי
CORS הוא שיחה בין הדפדפן שלך לשרת:
- דפדפן: "אני JavaScript ממקור X, רוצה לגשת למקור Y"
- שרת: "הנה התגובה שלי, והנה מי שאני סומך עליו" (דרך כותרות)
- דפדפן: "האם המקור X נמצא ברשימה? אם כן — ה-JavaScript מקבל את הנתונים. אם לא — חסום."
השרת תמיד מעבד את הבקשה. CORS שולט רק בשאלה האם הדפדפן ישתף את התגובה עם JavaScript.
זו הסיבה שטעויות CORS מרגישות הפוכות — אתה רואה ב-DevTools שהשרת הגיב בהצלחה, ובכל זאת הקוד שלך לא יכול לגשת אליו. התגובה קיימת. הדפדפן פשוט לא מרשה לך לקבל אותה.
שאלות נפוצות על CORS
למה הבקשה שלי עובדת ב-Postman אבל נכשלת בדפדפן?
Postman אינו דפדפן — הוא אינו אוכף CORS. CORS הוא תכונת אבטחה ספציפית לדפדפן שמונעת מ-JavaScript במקור אחד לגשת לתגובות ממקור אחר. כלים כמו curl ו-Postman מדלגים על בדיקה זו לחלוטין.
למה אני מקבל שגיאות CORS על localhost בזמן פיתוח?
http://localhost:3000 ו-http://localhost:8080 הם מקורות שונים (יציאות שונות). הממשק הקדמי והשרת שלך זקוקים להגדרת CORS מתאימה אפילו בפיתוח. מסגרות רבות כוללות מצבי פיתוח שמטפלים בכך אוטומטית.
האם אפשר להשבית את CORS?
לא ממש. ניתן להתקין הרחבות דפדפן שמסירות כותרות CORS לצורכי פיתוח, אבל זה משפיע רק על הדפדפן שלך. המשתמשים שלך עדיין יתקלו בשגיאות CORS. הפתרון האמיתי הוא הגדרת שרת נכונה.
למה הוספת כותרת Authorization פתאום שוברת את הבקשה שלי?
Authorization אינה כותרת "בטוחה", ולכן היא מפעילה בקשת preflight מסוג OPTIONS. השרת שלך חייב לטפל בבקשות OPTIONS ולהחזיר Access-Control-Allow-Headers מתאים הכולל Authorization.
למה לא ניתן להשתמש בתו כללי (*) עם פרטי אישור?
זה מכוון מבחינת אבטחה. אפשור פרטי אישור עם תו כללי פירושו "כל אתר יכול לשלוח בקשות מאומתות בשם המשתמש הזה" — חור אבטחה עצום. המפרט דורש התאמת מקור מפורשת כאשר פרטי אישור מעורבים.
此页面对您有帮助吗?