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

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

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

מה כותרות מותאמות אישית עושות בפועל

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

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

כותרות מותאמות אישית עונות על השאלות האלה:

X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-API-Version: 2024-10-01
X-Feature-Flag: experimental-ui

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

הקידומת X-: היסטוריה קצרה של כוונות טובות

כותרות מותאמות אישית מתחילות באופן מסורתי ב-"X-" כדי לסמן אותן כהרחבות:

X-Request-ID: 123
X-Powered-By: CustomServer/1.0

המוסכמה הגיעה מכותרות אימייל (RFC 822) ונראתה הגיונית — להבחין בבירור בין מותאם לסטנדרטי.

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

RFC 6648 (2012) ביטל רשמית את הקידומת X- לכותרות חדשות. ההמלצה כיום: פשוט השתמש בשמות תיאוריים.

Request-ID: 550e8400-e29b-41d4-a716-446655440000
API-Version: 2024-10-01

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

מעקב אחר בקשות: השימוש הקריטי ביותר

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

X-Request-ID: 550e8400-e29b-41d4-a716-446655440000

כל שירות מתעד את המזהה הזה עם כל פעולה:

[550e8400...] API Gateway: Received request
[550e8400...] Auth Service: Token validated
[550e8400...] User Service: Fetching profile
[550e8400...] Database: Query timeout after 30s
[550e8400...] User Service: Error - upstream timeout
[550e8400...] API Gateway: Returning 500

חפש את המזהה הזה ותראה את הסיפור המלא. מסד הנתונים פג זמן. שירות המשתמשים לא הצליח להתאושש. ה-Gateway החזיר שגיאה. בלי המזהה, היית מתאם חותמות זמן ומנחש.

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

function requestIdMiddleware(request, response, next) {
    const requestId = request.headers['x-request-id'] || generateUUID();
    request.requestId = requestId;
    response.set('X-Request-ID', requestId);
    next();
}

ניהול גרסאות API

APIs מתפתחים. לקוחות ישנים מפסיקים לעבוד. כותרות מותאמות אישית מציעות פתרון אחד:

GET /api/users
API-Version: 2024-10-01

אותה נקודת קצה משרתת תגובות שונות בהתאם לכותרת הגרסה. השווה זאת לניהול גרסאות ב-URL:

GET /api/v2/users

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

דגלי תכונות

כותרות יכולות לשלוט באילו תכונות בקשה רואה:

X-Feature-Flags: new-checkout,experimental-search

זה מאפשר:

  • בדיקות A/B: ניתוב משתמשים שונים לחוויות שונות
  • פריסות הדרגתיות: הפעלת תכונות ל-1% מהתנועה, ואז 10%, ואז לכולם
  • פיתוח: בדיקת תכונות חדשות בסביבת ייצור מבלי לחשוף אותן

השרת בודק את הדגלים ומתאים את ההתנהגות בהתאם.

מידע על הגבלת קצב

APIs לעיתים קרובות מודיעים ללקוחות כמה קיבולת נותרה להם:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1609459200

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

כותרות פרוקסי: הסטנדרטים דה פקטו

כמה כותרות מותאמות אישות כה נפוצות שהן למעשה סטנדרטיות.

X-Forwarded-For עוקבת אחר כתובות IP של לקוחות דרך שרשראות פרוקסי:

X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178

כל פרוקסי מוסיף את כתובת ה-IP שממנה קיבל את הבקשה. הערך השמאלי ביותר הוא הלקוח המקורי.

X-Forwarded-Proto מתעד את הפרוטוקול המקורי:

X-Forwarded-Proto: https

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

X-Real-IP היא החלופה הפשוטה יותר של nginx — רק כתובת ה-IP המקורית של הלקוח:

X-Real-IP: 203.0.113.195

עיצוב כותרות מותאמות אישית טובות

השתמש בשמות ברורים ותיאוריים:

// ברור
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-API-Version: 2024-10-01

// קריפטי
X-Req: 550e8400-e29b-41d4-a716-446655440000
X-V: 2024-10-01

מטרה אחת לכל כותרת:

// טוב
X-Request-ID: 550e8400
X-User-ID: user-123

// בעייתי
X-Context: requestId=550e8400,userId=user-123

שמור אותן קטנות. לכותרות יש מגבלות מעשיות (בדרך כלל 8KB סך הכל). העבר נתונים גדולים לגוף הבקשה.

טפל בהיעדר כותרות בצורה נאותה:

const apiVersion = request.headers['x-api-version'] || '2024-10-01';

CORS וכותרות מותאמות אישית

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

השרת חייב לאפשר אותן במפורש בתגובות preflight:

Access-Control-Allow-Headers: X-Request-ID, X-API-Version

כדי שלקוחות יוכלו לקרוא כותרות תגובה מותאמות, יש לחשוף אותן:

Access-Control-Expose-Headers: X-Request-ID, X-RateLimit-Remaining

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

אבטחה

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

// מסוכן
X-Admin-Token: secret-admin-token
X-Database-Connection: production-master

// בטוח
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000

אמת הכל. כותרות מותאמות אישית הן קלט משתמש:

const apiVersion = request.headers['x-api-version'];

if (!/^\d{4}-\d{2}-\d{2}$/.test(apiVersion)) {
    return response.status(400).json({ error: 'Invalid API version format' });
}

יישום

שליחת כותרות מותאמות אישות (לקוח):

fetch('/api/data', {
    headers: {
        'X-Request-ID': crypto.randomUUID(),
        'X-API-Version': '2024-10-01'
    }
});

קריאת כותרות מותאמות אישות (שרת):

app.get('/api/data', function(request, response) {
    const requestId = request.headers['x-request-id'];
    const apiVersion = request.headers['x-api-version'];
    
    response.set('X-Request-ID', requestId);
    response.json({ data: 'value' });
});

נקודות עיקריות

  • כותרות מותאמות אישות נושאות מטא-נתונים ספציפיים לאפליקציה שכותרות סטנדרטיות לא מתייחסות אליהם
  • הקידומת X- מיושנת לכותרות חדשות, אך נפוצה מאוד במערכות קיימות
  • מזהי בקשות חיוניים לניפוי באגים במערכות מבוזרות — צור בנקודת הכניסה, הפץ לכל מקום
  • כותרות X-Forwarded-* הן למעשה סטנדרטיות לשימור מידע לקוח דרך פרוקסים
  • CORS דורש הרשאה מפורשת לכותרות מותאמות אישות בבקשות חוצות-מקור
  • לעולם אל תשים נתונים רגישים בכותרות — הן מתועדות בכל מקום
  • אמת ערכי כותרות מותאמות אישות כמו כל קלט משתמש אחר

שאלות נפוצות על כותרות מותאמות אישות

האם עלי להשתמש בקידומת X- לכותרות מותאמות אישות חדשות?

לא. RFC 6648 ביטל את הקידומת X- בשנת 2012. השתמש בשמות תיאוריים ללא הקידומת: Request-ID במקום X-Request-ID. הסיבה היחידה להשתמש ב-X- היא עקביות עם כותרות קיימות במערכת שלך שכבר משתמשות בה.

כיצד מאבחנים בעיות כשמזהי בקשות אינם מועברים כראוי?

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

מה הגודל המרבי של כותרות מותאמות אישות?

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

מדוע ה-JavaScript שלי לא יכול לקרוא כותרות תגובה מותאמות?

CORS. דפדפנים חושפים רק כותרות תגובה "פשוטות" ל-JavaScript כברירת מחדל. השרת חייב לכלול את הכותרות המותאמות שלך ב-Access-Control-Expose-Headers עבור בקשות חוצות-מקור. לבקשות מאותו מקור אין הגבלה זו.

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

😔
🤨
😃