מניעת בקשות רשת מיותרות באמצעות מטמון ה-HTTP

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

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

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

במדריך הזה תלמדו את העקרונות הבסיסיים של הטמעה יעילה של שמירה במטמון HTTP.

תאימות דפדפן

אין למעשה ממשק API אחד שנקרא 'מטמון HTTP'. זה השם הכללי של אוסף ממשקי API בפלטפורמת האינטרנט. ממשקי ה-API האלה נתמכים בכל הדפדפנים:

Cache-Control

תמיכה בדפדפן

  • Chrome: 1.
  • קצה: 12.
  • Firefox: 1.
  • Safari: 1.

מקור

ETag

תמיכה בדפדפן

  • Chrome: 1.
  • קצה: 12.
  • Firefox: 1.
  • Safari: 1.

מקור

Last-Modified

תמיכה בדפדפן

  • Chrome: 1.
  • קצה: 12.
  • Firefox: 1.
  • Safari: 1.

מקור

איך פועל מטמון HTTP

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

ההתנהגות של מטמון HTTP נשלטת על ידי שילוב של כותרות בקשות וכותרות תשובות. בתרחיש אידיאלי, תהיה לכם שליטה גם על הקוד של אפליקציית האינטרנט (שיקבע את כותרות הבקשות) וגם על התצורה של שרת האינטרנט (שיקבעו את כותרות התגובה).

לסקירה מפורטת יותר של מושגים אפשר לעיין במאמר שמירה במטמון HTTP של ה-MDN.

כותרות של בקשות: להישאר עם ברירות המחדל (בדרך כלל)

יש כמה כותרות חשובות שצריך לכלול בבקשות היוצאות של אפליקציית האינטרנט שלכם, אבל הדפדפן כמעט תמיד מגדיר אותן בשבילכם כשהוא שולח בקשות. כותרות של בקשות שמשפיעות על בדיקת העדכניות, כמו If-None-Match ו-If-Modified-Since, מופיעות בהתאם להבנה של הדפדפן לגבי הערכים הנוכחיים במטמון ה-HTTP.

אלה חדשות טובות — המשמעות היא שאפשר להמשיך לכלול תגים כמו <img src="my-image.png"> ב-HTML, והדפדפן יטפל עבורכם אוטומטית בשמירת HTTP במטמון, ללא מאמץ נוסף.

כותרות תגובה: הגדרת שרת האינטרנט

החלק החשוב ביותר בהגדרת שמירת ה-HTTP במטמון הוא הכותרות ששרת האינטרנט מוסיף לכל תגובה יוצאת. הכותרות הבאות מביאות בחשבון את ההתנהגות היעילה של השמירה במטמון:

  • Cache-Control השרת יכול להחזיר הוראת Cache-Control כדי לציין איך ולמשך כמה זמן צריך לשמור את התגובה הבודדת במטמון של הדפדפן ומטמון ביניים אחרים.
  • ETag כשהדפדפן מוצא תגובה שנשמרה במטמון שפג תוקפה, הוא יכול לשלוח לשרת אסימון קטן (בדרך כלל גיבוב (hash) של תוכן הקובץ) כדי לבדוק אם הקובץ השתנה. אם השרת מחזיר את אותו אסימון, הקובץ זהה ואין צורך להוריד אותו מחדש.
  • Last-Modified הכותרת הזו משמשת לאותה מטרה כמו ETag, אבל היא משתמשת באסטרטגיה מבוססת-זמן כדי לקבוע אם משאב השתנה, בניגוד לאסטרטגיה מבוססת-התוכן של ETag.

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

כדי לחסוך לכם חיפושים, הנה הוראות להגדרה של כמה שרתי אינטרנט פופולריים:

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

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

יש שני תרחישים חשובים שצריך להתייחס אליהם כשמגדירים את בכותרות התגובה של שרת האינטרנט.

שמירה במטמון לטווח ארוך של כתובות URL שיש להן גרסאות

נניח שהשרת מורה לדפדפנים לשמור קובץ CSS במטמון למשך שנה (Cache-Control: max-age=31536000), אבל המעצב ביצע עדכון למקרה חירום שצריך לפרוס באופן מיידי. איך מודיעים לדפדפנים לעדכן את ה'לא פעיל' עותק של הקובץ שנשמר במטמון? אי אפשר, לפחות לא בלי לשנות את כתובת ה-URL של המשאב.

אחרי שהדפדפן שומר את התגובה במטמון, נעשה שימוש בגרסת המטמון עד שהיא מפסיקה לפעול, כפי שנקבע על ידי max-age או expires, או עד שהיא מוסרת מהמטמון מסיבה אחרת כלשהי. למשל, על ידי ניקוי המטמון של הדפדפן. כתוצאה מכך, משתמשים שונים עשויים להשתמש בגרסאות שונות של הקובץ בזמן בניית הדף: משתמשים שאחזרו את המשאב משתמשים בגרסה החדשה, ומשתמשים ששמרו במטמון עותק קודם (אבל עדיין חוקי) משתמשים בגרסה ישנה יותר של התגובה שלו.

איך אפשר לנצל את שני העולמות: שמירה במטמון בצד הלקוח ועדכונים מהירים? אתם משנים את כתובת ה-URL של המשאב ומאלצים את המשתמש להוריד את התגובה החדשה בכל פעם שהתוכן שלה משתנה. בדרך כלל אפשר לעשות זאת על ידי הטמעת טביעת אצבע של הקובץ או מספר גרסה שלו, בשם הקובץ שלו – לדוגמה style.x234dff.css.

כשמגיבים לבקשות לכתובות URL שמכילות 'טביעת אצבע' או מידע על ניהול גרסאות, והתוכן שלהם לא אמור להשתנות, צריך להוסיף את Cache-Control: max-age=31536000 לתשובות שלך.

הגדרת הערך הזה מנחה את הדפדפן שכשהוא יצטרך לטעון את אותה כתובת URL במהלך השנה הבאה (31,536,000 שניות, הערך המקסימלי הנתמך), הוא יוכל להשתמש באופן מיידי בערך ששמור במטמון ה-HTTP, בלי שתצטרכו להגיש בקשת רשת לשרת האינטרנט שלכם. זה נהדר - כך הבנתם מיד את האמינות והמהירות כתוצאה מההימנעות מהרשת!

כלים כמו Webpack יכולים לבצע אוטומציה של תהליך ההקצאה של טביעות אצבע שעברו גיבוב (hash) לכתובות ה-URL של הנכסים.

אימות מחדש של שרת לכתובות URL ללא גרסאות

לצערנו, לא לכל כתובות ה-URL שטוענים יש גרסאות. יכול להיות שלא תוכלו לכלול שלב build לפני הפריסה של אפליקציית האינטרנט, ולכן לא תוכלו להוסיף גיבובים לכתובות ה-URL של הנכסים. וכל אפליקציית אינטרנט זקוקה לקובצי HTML - הקבצים האלה (כמעט!) לא יכללו מידע על ניהול גרסאות, מפני שאף אחד לא יטרח להשתמש באפליקציית האינטרנט שלך אם יהיה צריך לזכור שכתובת ה-URL כדי להיכנס אליה היא https://example.com/index.34def12.html. אז מה אפשר לעשות לגבי כתובות ה-URL האלה?

זהו תרחיש אחד שבו תצטרכו להכיר בהפסד שלכם. השמירה במטמון HTTP לבדו לא חזקה מספיק כדי להימנע לגמרי מהרשת. (אל דאגה, בקרוב תלמדו על קובץ השירות (service worker), שיספק את התמיכה הדרושה כדי להילחם לטובתכם.) עם זאת, יש כמה פעולות שאפשר לבצע כדי להבטיח שבקשות הרשת יהיו מהירות ויעילות ככל האפשר.

הערכים הבאים של Cache-Control יכולים לעזור לך לכוונן בצורה עדינה את המיקום והאופן שבו כתובות URL שאין להן גרסאות נשמרות במטמון:

  • no-cache הפעולה הזו מורה לדפדפן לאמת מחדש מול השרת בכל פעם שהוא משתמש בגרסה שנשמרה במטמון של כתובת ה-URL.
  • no-store הפעולה הזו מורה לדפדפן ולמטמון ביניים אחרים (כמו CDN) לעולם לא לאחסן אף גרסה של הקובץ.
  • private דפדפנים יכולים לשמור את הקובץ במטמון, אבל מטמון ביניים לא יכול לעשות זאת.
  • public התגובה יכולה להישמר במטמון בכל מטמון.

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

גם הגדרה של ETag או Last-Modified יכולה לעזור. כפי שצוין בכותרות התגובות, ETag ו-Last-Modified משרתים את אותה מטרה: לקבוע אם הדפדפן צריך להוריד מחדש קובץ שנשמר במטמון שפג תוקפו. מומלץ להשתמש בETag כי היא מדויקת יותר.

נניח שחלפו 120 שניות מאז השליפה הראשונית, והדפדפן שלח בקשה חדשה לגבי אותו משאב. ראשית, הדפדפן בודק את מטמון ה-HTTP ומוצא את התגובה הקודמת. לצערנו, הדפדפן לא יכול להשתמש בתשובה הקודמת כי פג התוקף של התשובה. בשלב הזה, הדפדפן יוכל לשלוח בקשה חדשה ולאחזר את התגובה המלאה החדשה. עם זאת, הפעולה הזו לא יעילה כי אם המשאב לא השתנה, אין סיבה להוריד את אותו המידע שכבר נמצא במטמון!

זו הבעיה שאסימוני אימות, כפי שמצוין בכותרת ETag, נועדו לפתור. השרת יוצר ומחזיר אסימון שרירותי, שהוא בדרך כלל גיבוב (hash) או טביעת אצבע אחרת של תוכן הקובץ. הדפדפן לא צריך לדעת איך טביעת האצבע נוצרת. הוא צריך לשלוח אותו לשרת רק בבקשה הבאה. אם טביעת האצבע לא השתנתה, המשאב לא השתנה והדפדפן יכול לדלג על ההורדה.

אם מגדירים את ETag או Last-Modified, בקשת האימות מחדש יכולה להיות יעילה הרבה יותר כי היא מאפשרת לה להפעיל את כותרות הבקשות If-Modified-Since או If-None-Match שהוזכרו בכותרות של בקשות.

כששרת אינטרנט שהוגדר כראוי רואה את הכותרות של הבקשות הנכנסות, הוא יכול לאשר אם הגרסה של המשאב שכבר נמצא במטמון ה-HTTP של הדפדפן תואמת לגרסה האחרונה בשרת האינטרנט. אם יש התאמה, השרת יכול להגיב באמצעות תגובת HTTP 304 Not Modified, המקבילה למילים "היי, ממשיכים להשתמש במה שכבר קיבלת!" יש מעט מאוד נתונים להעביר בעת שליחת תגובה מהסוג הזה, לכן בדרך כלל התהליך מהיר בהרבה מהצורך לשלוח בחזרה עותק של המשאב עצמו.

תצוגה חזותית של לקוח שמבקש משאב והשרת מגיב עם כותרת 304.
הדפדפן מבקש /file מהשרת, והוא כולל את הכותרת If-None-Match כדי להורות לשרת להחזיר את הקובץ המלא רק אם ETag של הקובץ בשרת לא תואם לערך If-None-Match של הדפדפן. במקרה הזה, 2 הערכים תואמים, ולכן השרת מחזיר תגובת 304 Not Modified עם הוראות לגבי משך הזמן לשמירת הקובץ במטמון (Cache-Control: max-age=120).

סיכום

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

ההגדרות הבאות של Cache-Control יכולות להיות התחלה טובה:

  • Cache-Control: no-cache למשאבים שצריך לאמת מחדש מול השרת לפני כל שימוש.
  • Cache-Control: no-store למשאבים שאף פעם לא צריכים להישמר במטמון.
  • Cache-Control: max-age=31536000 למשאבים עם גרסאות.

בנוסף, הכותרת ETag או Last-Modified יכולה לעזור לך לאמת מחדש ביעילות רבה יותר משאבי מטמון שתוקפם פג.

מידע נוסף

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

במאמר שימוש במטמון המטמון מוסבר איך לבצע אופטימיזציה של השימוש במטמון למבקרים חוזרים.

נספח: טיפים נוספים

אם יש לכם יותר זמן, הנה עוד דרכים שבהן תוכלו לבצע אופטימיזציה של השימוש במטמון ה-HTTP:

  • השתמשו בכתובות URL עקביות. אם מציגים תוכן זהה בכתובות URL שונות, התוכן יאוחזר ויאוחסן מספר פעמים.
  • צמצום הנטישה. אם חלק ממשאב (כמו קובץ CSS) מתעדכן לעיתים קרובות, ואילו שאר הקובץ לא מתעדכן (כמו קוד ספרייה), כדאי לפצל את הקוד שעודכן לעיתים קרובות לקובץ נפרד ולהשתמש באסטרטגיית שמירה במטמון למשך זמן קצר בשביל הקוד שמתעדכן לעיתים קרובות, ואסטרטגיה למשך זמן ארוך של שמירה במטמון לקוד שלא משתנה לעיתים קרובות.
  • אם אפשר להגדיר מידה מסוימת של חוסר פעילות במדיניות Cache-Control, כדאי לעיין בהנחיה החדשה stale-while-revalidate.

נספח: תרשים זרימה של Cache-Control

תרשים זרימה
תהליך ההחלטה לגבי הגדרת הכותרות של Cache-Control.

נספח: Cache-Control דוגמאות

ערך של Cache-Control הסבר
max-age=86400 אפשר לשמור את התגובה במטמון על ידי דפדפנים ומטמון ביניים למשך עד יום אחד (60 שניות x 60 דקות x 24 שעות).
private, max-age=600 הדפדפן יכול לשמור את התגובה במטמון (אבל לא במטמון ביניים) למשך עד 10 דקות (60 שניות x 10 דקות).
public, max-age=31536000 אפשר לשמור את התגובה בכל מטמון למשך שנה.
no-store אי אפשר לשמור את התגובה במטמון ויש לאחזר אותה במלואה בכל בקשה.