עודכן לפני חודש
כל תגובת HTTP נושאת שאלה שהדפדפן זקוק לתשובה עליה לפני שיוכל לעשות דבר שימושי: "מה אני רואה כאן?"
כותרת ה-Content-Type מספקת את התשובה הזו. בלעדיה, אותם בייטים שמציגים תצלום הופכים לזבל חסר משמעות — או גרוע מכך, לקוד להרצה שהדפדפן לא ציפה לבצע.
מה Content-Type עושה בפועל
Content-Type מציין את סוג המדיה (הנקרא גם סוג MIME) של הנתונים המועברים. הוא מופיע הן בבקשות והן בתגובות:
בתגובות, הוא אומר לדפדפן כיצד לפרש את מה שקיבל:
בבקשות, הוא אומר לשרת כיצד לנתח את מה שאתם שולחים:
טעו בזה והדברים ייפלו בשקט. שלחו JSON עם Content-Type שגוי והשרת שלכם לא ינתח אותו. הגישו תמונה עם text/html וצפו בדפדפן שמנסה לרנדר נתונים בינאריים כדף אינטרנט.
מבנה סוג MIME
MIME הוא ראשי תיבות של "Multipurpose Internet Mail Extensions" — תוכנן במקור עבור דואר אלקטרוני, ואומץ על ידי HTTP. הפורמט פשוט:
הסוג הוא הקטגוריה הרחבה. תת-הסוג הוא הפורמט הספציפי:
text/html— קטגוריית טקסט, פורמט HTMLimage/png— קטגוריית תמונה, פורמט PNGapplication/json— קטגוריית אפליקציה, פורמט JSON
חלק מסוגי ה-MIME כוללים פרמטרים:
סוגי 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/webp | WebP (פורמט מודרני ויעיל) |
וידאו ואודיו
| סוג MIME | שימוש |
|---|---|
video/mp4 | סרטוני MP4 |
video/webm | סרטוני WebM |
audio/mpeg | אודיו MP3 |
audio/wav | אודיו WAV |
Multipart
multipart/form-data הוא מיוחד — הוא מאפשר ערבוב של סוגי תוכן שונים בבקשה אחת, חיוני לטפסים שכוללים גם שדות טקסט וגם העלאות קבצים:
קידוד תווים
עבור תוכן טקסט, הפרמטר charset מציין כיצד מקודדים התווים:
השתמשו תמיד ב-UTF-8. הוא תומך בכל תו מכל שפה, הוא תואם לאחור עם ASCII, והוא הסטנדרט האוניברסלי. קידודים אחרים כמו ISO-8859-1 או Shift_JIS קיימים לתאימות עם מערכות ישנות, אך אלא אם אתם מתחזקים מערכות עתיקות, UTF-8 הוא התשובה.
השמטת ה-charset מכריחה דפדפנים לנחש, וניחוש מוביל לטקסט מקולקל — ה"מוג'יבאקה" המפורסם שבו תווים בינלאומיים הופכים לסימני שאלה או סמלים אקראיים.
הסכמה על פורמט תוכן
לקוחות יכולים לבקש פורמטים ספציפיים באמצעות כותרת ה-Accept:
הפרמטר q מציין את ההעדפה (0 עד 1). כאן, JSON הוא המועדף ביותר (q=1.0 מרומז), XML מקובל (q=0.9), וכל דבר אחר הוא מוצא אחרון (q=0.8).
השרת בוחן זאת ומגיב עם ההתאמה הטובה ביותר. זה מאפשר לנקודת קצה API אחת לשרת JSON לאפליקציות ווב ו-XML למערכות ישנות, בהתאם למה שכל לקוח מבקש.
מדוע טעות בזה היא מסוכנת
פגיעויות אבטחה
תוכן שמסומן בצורה שגויה יכול להפוך את הדפדפן שלכם לשותף לפשע בלי ידיעתו:
- תוקף מעלה קובץ HTML המכיל JavaScript זדוני
- השרת שומר אותו, אולי בתור "profile-picture.jpg"
- השרת מגיש אותו עם
Content-Type: text/html - הדפדפן מבצע בנאמנות את ה-JavaScript — מתקפת XSS הושלמה
כותרת X-Content-Type-Options: nosniff מונעת מדפדפנים לפקפק ב-Content-Type. עם כותרת זו, הדפדפן סומך על הצהרתכם באופן מוחלט — אז עדיף שתצדקו.
כשלי API שקטים
זה אחד מכאבי הראש הנפוצים ביותר בניפוי באגים:
השרת רואה את ה-Content-Type, מחליט כיצד לנתח את גוף הבקשה, ואם הם לא תואמים, הנתונים שלכם מגיעים כשטות.
הורדות ותצוגות שבורות
דפדפנים מחליטים מה לעשות בהתבסס לחלוטין על Content-Type:
text/html→ נתח ורנדר כדף אינטרנטapplication/json→ הצג טקסט גולמי (או הצע הורדה)image/png→ רנדר כתמונה בשורהapplication/pdf→ פתח צופה PDFapplication/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. (ספציפי לספק):
דוגמת GitHub API זו מקודדת את הספק (GitHub), הגרסה (v3), והפורמט הבסיסי (JSON) — הכל בסוג אחד. שימושי לגרסאות API ולפורמטים קנייניים.
ניפוי באגים בבעיות Content-Type
כלי הפיתוח של הדפדפן (DevTools) עושים את זה גלוי:
- פתחו את DevTools (F12)
- עברו לכרטיסיית Network
- לחצו על כל בקשה
- בדקו את חלק ה-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 לשלוט על התנהגות ההורדה.
האם דף זה היה מועיל?