1. ספרייה
  2. HTTP והרשת
  3. שיטות HTTP

עודכן לפני חודש

שיטת OPTIONS שואלת שרתים שאלה פשוטה: "מה אני יכול לעשות עם המשאב הזה?" אבל זו התשובה המשעממת.

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

זו בקשת ה-preflight — ו-OPTIONS היא זו שעושה את השאילה.

מה OPTIONS באמת מחזירה

בקשות OPTIONS מחזירות מידע על מה שמותר:

OPTIONS /api/articles/12345 HTTP/1.1
Host: api.example.com
→
HTTP/1.1 204 No Content
Allow: GET, HEAD, PUT, DELETE, OPTIONS
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400

הכותרת Allow מפרטת כל שיטה שהשרת תומך בה עבור משאב זה. כותרות Access-Control-* הן עבור CORS — הן מודיעות לדפדפנים אילו בקשות cross-origin מותרות.

ריקוד ה-Preflight

כאן OPTIONS מוכיחה את עצמה.

כאשר JavaScript ב-https://app.example.com רוצה לשלוח את הבקשה הזו:

fetch('https://api.example.com/articles/123', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token123'
  },
  body: JSON.stringify({ title: 'Updated Title' })
});

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

לכן הדפדפן שולח אוטומטית preflight:

OPTIONS /articles/123 HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization

תרגום: "JavaScript מ-app.example.com רוצה לבצע PUT עם הכותרות האלה. לאשר?"

השרת עונה:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

"כן, המקור הזה יכול לבצע PUT עם אותן כותרות. ואתה יכול לזכור את התשובה הזו למשך 24 שעות."

רק אז הדפדפן שולח את בקשת ה-PUT בפועל.

למה בקשות מסוימות מדלגות על Preflight

לא כל בקשת cross-origin מפעילה OPTIONS. "בקשות פשוטות" עוברות ישירות:

  • שיטה: GET, HEAD, או POST
  • כותרות: רק בסיסיות כמו Accept, Accept-Language, Content-Type
  • Content-Type: רק application/x-www-form-urlencoded, multipart/form-data, או text/plain

אלה משקפות את מה שטפסי HTML תמיד יכלו לעשות — לפני JavaScript, לפני fetch, לפני APIs. הדפדפן מתייחס אליהן כבטוחות מפני שהן תמיד היו אפשריות.

כל דבר אחר מפעיל preflight:

// ללא preflight (GET פשוט)
fetch('https://api.example.com/data');

// עם preflight (DELETE אינה פשוטה)
fetch('https://api.example.com/data', { method: 'DELETE' });

// עם preflight (כותרת Authorization אינה פשוטה)
fetch('https://api.example.com/data', {
  headers: { 'Authorization': 'Bearer token' }
});

// עם preflight (סוג תוכן JSON אינו פשוט)
fetch('https://api.example.com/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ data: 'value' })
});

שמירת תגובות Preflight במטמון

Access-Control-Max-Age: 86400 מנחה דפדפנים לשמור את תגובת ה-preflight במטמון. בלי זה, כל PUT או DELETE ידרוש שני מעברי הלוך-חזור — OPTIONS ואז הבקשה בפועל.

אבל דפדפנים מטילים מגבלות משלהם1:

דפדפןמטמון מקסימלי
Firefox24 שעות
Chrome2 שעות
Safari5 דקות

הגדר את max-age שלך ל-86400 (24 שעות) ותן לדפדפנים להחיל את המגבלות שלהם. ברירת המחדל היא רק 5 שניות.

מימוש OPTIONS

רוב הפריימוורקים מטפלים ב-OPTIONS אוטומטית:

// Express עם middleware של CORS
const cors = require('cors');

app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  maxAge: 86400
}));

אם אתה מממש זאת ידנית:

app.options('/api/articles/:id', (req, res) => {
  res.set('Allow', 'GET, HEAD, PUT, DELETE, OPTIONS');
  res.set('Access-Control-Allow-Origin', req.get('Origin'));
  res.set('Access-Control-Allow-Methods', 'GET, PUT, DELETE');
  res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.set('Access-Control-Max-Age', '86400');
  res.status(204).end();
});

OPTIONS לגילוי כלל-שרתי

ניתן לשלוח OPTIONS ל-* כדי לשאול את השרת כולו:

OPTIONS * HTTP/1.1
Host: api.example.com
→
HTTP/1.1 200 OK
Allow: GET, POST, PUT, DELETE, HEAD, OPTIONS

זה שואל "אילו שיטות השרת הזה תומך בהן בכלל?" במקום "מה אני יכול לעשות עם המשאב הספציפי הזה?"

אבטחה: הסכנות האמיתיות

OPTIONS צריכה לכבד אימות. אל תחשוף שמשאבים סודיים קיימים:

OPTIONS /admin/secret-data HTTP/1.1
→ 401 Unauthorized (אם לא מאומת)
→ 403 Forbidden (אם לא מורשה)

לעולם אל תחזיר Allow: GET, PUT, DELETE עבור משאבים שהמשתמש לא אמור לדעת על קיומם.

הטעות המסוכנת ביותר ב-CORS אינה שימוש בתו כללי — דפדפנים חוסמים Access-Control-Allow-Origin: * בשילוב עם Access-Control-Allow-Credentials: true על פי עיצוב2. הסכנה האמיתית היא שיקוף מקור: החזרה דינמית של כל כותרת Origin שמתקבלת.

// מסוכן: שיקוף מקור
res.set('Access-Control-Allow-Origin', req.get('Origin'));
res.set('Access-Control-Allow-Credentials', 'true');

זה מאפשר לכל אתר לשלוח בקשות מאומתות ל-API שלך. תמיד אמת מקורות מול רשימה מאושרת:

const allowedOrigins = [
  'https://app.example.com',
  'https://mobile.example.com'
];

const origin = req.get('Origin');
if (allowedOrigins.includes(origin)) {
  res.set('Access-Control-Allow-Origin', origin);
  res.set('Access-Control-Allow-Credentials', 'true');
}

ניפוי שגיאות CORS עם OPTIONS

כאשר CORS נכשל בצורה מסתורית, OPTIONS הוא כלי האבחון שלך:

curl -X OPTIONS https://api.example.com/resource \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: PUT" \
  -H "Access-Control-Request-Headers: Content-Type" \
  -i

זה מראה לך בדיוק מה השרת מאפשר — או מדוע הוא דוחה את ה-preflight שלך.

נקודות מפתח

  • OPTIONS שואלת "מה אני יכול לעשות עם המשאב הזה?" ומחזירה שיטות מותרות בכותרת Allow.
  • מטרתה האמיתית היא preflight של CORS: הדפדפן שואל שרתים רשות לפני שהוא מאפשר ל-JavaScript לשלוח בקשות cross-origin.
  • בקשות פשוטות (GET, HEAD, POST בסיסיים עם כותרות פשוטות) מדלגות על preflight. כל השאר מפעיל אותו.
  • שמור תגובות preflight במטמון עם Access-Control-Max-Age להפחתת מעברי הלוך-חזור. דפדפנים מגבילים זאת בין 5 דקות (Safari) ל-24 שעות (Firefox).
  • אל תדלוף מידע — כבד אימות בתגובות OPTIONS בדיוק כמו בכל שיטה אחרת.
  • הדפדפן הוא שומר הסף. OPTIONS היא הדרך שבה שרתים מגידים לדפדפן מה לאפשר לעבור.

שאלות נפוצות על HTTP OPTIONS

מדוע ה-API שלי מקבל בקשת OPTIONS לפני כל PUT או DELETE?

זו בדיקת preflight של הדפדפן. כאשר JavaScript שולח בקשת cross-origin שעלולה לשנות נתונים (או משתמש בכותרות מותאמות), הדפדפן שולח אוטומטית OPTIONS תחילה כדי לוודא שהשרת מאפשר זאת. זה לא משהו שהקוד שלך עושה — זה הדפדפן שמגן על שרתים מפני JavaScript שעלול להיות זדוני.

איך אני עוצר את בקשות ה-preflight?

אתה לא יכול לבטל אותן עבור בקשות שדורשות אותן — אבטחת הדפדפן פועלת כפי שתוכננה. אבל ניתן להפחית את תדירותן על ידי הגדרת Access-Control-Max-Age בתגובות, שמנחה דפדפנים לשמור את תוצאת ה-preflight במטמון. ניתן גם לבנות את ה-API לשימוש בבקשות פשוטות ככל האפשר (GET, POST עם סוגי תוכן בסגנון טופס).

מדוע CORS קיים? נראה שזה רק מקשה על הפיתוח.

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

מקורות

האם דף זה היה מועיל?

😔
🤨
😃
שיטת HTTP OPTIONS • ספרייה • Connected