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

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

כל תגובת HTTP נושאת שאלה שהדפדפן זקוק לתשובה עליה לפני שיוכל לעשות דבר שימושי: "מה אני רואה כאן?"

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

מה Content-Type עושה בפועל

Content-Type מציין את סוג המדיה (הנקרא גם סוג MIME) של הנתונים המועברים. הוא מופיע הן בבקשות והן בתגובות:

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

Content-Type: text/html; charset=utf-8

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

Content-Type: application/json

טעו בזה והדברים ייפלו בשקט. שלחו JSON עם Content-Type שגוי והשרת שלכם לא ינתח אותו. הגישו תמונה עם text/html וצפו בדפדפן שמנסה לרנדר נתונים בינאריים כדף אינטרנט.

מבנה סוג MIME

MIME הוא ראשי תיבות של "Multipurpose Internet Mail Extensions" — תוכנן במקור עבור דואר אלקטרוני, ואומץ על ידי HTTP. הפורמט פשוט:

type/subtype

הסוג הוא הקטגוריה הרחבה. תת-הסוג הוא הפורמט הספציפי:

  • text/html — קטגוריית טקסט, פורמט HTML
  • image/png — קטגוריית תמונה, פורמט PNG
  • application/json — קטגוריית אפליקציה, פורמט JSON

חלק מסוגי ה-MIME כוללים פרמטרים:

text/html; charset=utf-8
multipart/form-data; boundary=----WebKitFormBoundary

סוגי MIME נפוצים

טקסט

סוג MIMEשימוש
text/htmlדפי אינטרנט HTML
text/plainטקסט רגיל ללא עיצוב
text/cssגיליונות סגנון CSS
text/javascriptקוד JavaScript

אפליקציה

סוג MIMEשימוש
application/jsonנתוני JSON (הסטנדרט ל-API מודרניים)
application/xmlנתוני XML
application/pdfמסמכי PDF
application/zipארכיוני ZIP
application/octet-streamבינארי גנרי (כאשר הסוג הספציפי אינו ידוע)
application/x-www-form-urlencodedנתוני טופס מקודדים כפרמטרי URL

תמונות

סוג MIMEשימוש
image/pngתמונות PNG
image/jpegתמונות JPEG
image/gifתמונות GIF
image/svg+xmlגרפיקה וקטורית SVG
image/webpWebP (פורמט מודרני ויעיל)

וידאו ואודיו

סוג MIMEשימוש
video/mp4סרטוני MP4
video/webmסרטוני WebM
audio/mpegאודיו MP3
audio/wavאודיו WAV

Multipart

multipart/form-data הוא מיוחד — הוא מאפשר ערבוב של סוגי תוכן שונים בבקשה אחת, חיוני לטפסים שכוללים גם שדות טקסט וגם העלאות קבצים:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

קידוד תווים

עבור תוכן טקסט, הפרמטר charset מציין כיצד מקודדים התווים:

Content-Type: text/html; charset=utf-8

השתמשו תמיד ב-UTF-8. הוא תומך בכל תו מכל שפה, הוא תואם לאחור עם ASCII, והוא הסטנדרט האוניברסלי. קידודים אחרים כמו ISO-8859-1 או Shift_JIS קיימים לתאימות עם מערכות ישנות, אך אלא אם אתם מתחזקים מערכות עתיקות, UTF-8 הוא התשובה.

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

הסכמה על פורמט תוכן

לקוחות יכולים לבקש פורמטים ספציפיים באמצעות כותרת ה-Accept:

Accept: application/json, application/xml;q=0.9, */*;q=0.8

הפרמטר q מציין את ההעדפה (0 עד 1). כאן, JSON הוא המועדף ביותר (q=1.0 מרומז), XML מקובל (q=0.9), וכל דבר אחר הוא מוצא אחרון (q=0.8).

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

מדוע טעות בזה היא מסוכנת

פגיעויות אבטחה

תוכן שמסומן בצורה שגויה יכול להפוך את הדפדפן שלכם לשותף לפשע בלי ידיעתו:

  1. תוקף מעלה קובץ HTML המכיל JavaScript זדוני
  2. השרת שומר אותו, אולי בתור "profile-picture.jpg"
  3. השרת מגיש אותו עם Content-Type: text/html
  4. הדפדפן מבצע בנאמנות את ה-JavaScript — מתקפת XSS הושלמה

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

כשלי API שקטים

זה אחד מכאבי הראש הנפוצים ביותר בניפוי באגים:

// זה נכשל בשקט — השרת מקבל זבל
fetch('/api/users', {
    method: 'POST',
    headers: {
        'Content-Type': 'text/plain'  // שגוי!
    },
    body: JSON.stringify({ name: 'Alice' })
});

// זה עובד — Content-Type תואם לנתונים
fetch('/api/users', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: 'Alice' })
});

השרת רואה את ה-Content-Type, מחליט כיצד לנתח את גוף הבקשה, ואם הם לא תואמים, הנתונים שלכם מגיעים כשטות.

הורדות ותצוגות שבורות

דפדפנים מחליטים מה לעשות בהתבסס לחלוטין על Content-Type:

  • text/html → נתח ורנדר כדף אינטרנט
  • application/json → הצג טקסט גולמי (או הצע הורדה)
  • image/png → רנדר כתמונה בשורה
  • application/pdf → פתח צופה PDF
  • application/octet-stream → הצע להוריד

הגישו PDF עם text/html וצפו בדפדפן שמנסה לרנדר נתונים בינאריים כדף אינטרנט — מסך מלא בחרטא.

סיומות קבצים לא משנות (ל-HTTP)

סיומות קבצים כמו .jpg, .pdf, או .html הן מוסכמות עבור מערכות הפעלה. HTTP לא אכפת לו. כותרת ה-Content-Type היא האמת היחידה.

קובץ בשם vacation.jpg שמוגש עם Content-Type: application/pdf ייפתח כ-PDF. קובץ בשם malware.exe שמוגש עם Content-Type: image/png יוצג כתמונה (שבורה).

זה יוצר כלל ששווה לפעול לפיו: וודאו שהסיומות תואמות ל-Content-Type. לא מפני ש-HTTP דורש זאת, אלא מפני שבני האדם שמתחזקים את המערכת יודו לכם.

סוגי MIME מותאמים אישית

אפליקציות יכולות להגדיר סוגים מותאמים אישית, בדרך כלל עם הקידומת application/vnd. (ספציפי לספק):

Content-Type: application/vnd.github.v3+json

דוגמת GitHub API זו מקודדת את הספק (GitHub), הגרסה (v3), והפורמט הבסיסי (JSON) — הכל בסוג אחד. שימושי לגרסאות API ולפורמטים קנייניים.

ניפוי באגים בבעיות Content-Type

כלי הפיתוח של הדפדפן (DevTools) עושים את זה גלוי:

  1. פתחו את DevTools (F12)
  2. עברו לכרטיסיית Network
  3. לחצו על כל בקשה
  4. בדקו את חלק ה-Headers

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

שאלות נפוצות על Content-Type וסוגי MIME

מה קורה אם לא מגדירים כותרת Content-Type?

דפדפנים מנסים לנחש באמצעות "MIME sniffing" — בוחנים את הבייטים בפועל כדי להסיק את הסוג. זה לא אמין ומסוכן. קובץ טקסט המכיל תגיות <script> עלול להיות מזוהה כ-HTML ולהתבצע. הגדירו תמיד Content-Type באופן מפורש.

מדוע ה-JSON API שלי מחזיר "undefined" או נכשל בניתוח?

בדרך כלל מדובר בחוסר התאמה של Content-Type. או שאתם שולחים JSON עם Content-Type: text/plain, או שהשרת מגיב ללא Content-Type: application/json. בדקו את שני הכיוונים ב-DevTools.

מה ההבדל בין application/javascript לבין text/javascript?

text/javascript הוא המקורי, application/javascript הוא הסוג הנכון טכנית לפי RFC 4329. שניהם עובדים בכל מקום. השתמשו במה שהכלים שלכם מייצרים — זה אחד מהקרבות שלא שווה להילחם בהם.

האם כדאי להשתמש ב-application/octet-stream להורדות קבצים?

application/octet-stream הוא סוג ה"אני לא יודע מה זה" — הוא מפעיל הנחיה להורדה. השתמשו בו רק כאשר אתם באמת לא יודעים את סוג הקובץ. אחרת, השתמשו בסוג הספציפי (application/pdf, image/png, וכו׳) ותנו לכותרת Content-Disposition לשלוט על התנהגות ההורדה.

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

😔
🤨
😃