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

איליה גריגוריק
ג'ף פוזניק
ג'ף פוזניק

שליפה של משאבים מהרשת היא תהליך איטי ויקר:

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

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

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

תאימות דפדפן

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

איך כתובות URL עם גרסאות יכולות לעזור לאסטרטגיית השמירה במטמון
מומלץ להשתמש בכתובות 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 בלבד אינה חזקה מספיק כדי למנוע לגמרי את הרשת. (אל דאגה – בקרוב תלמדו על עובדי שירות, שיספקו את התמיכה הדרושה לנו כדי להניע את הקרב בחזרה לטובתכם). עם זאת, יש כמה פעולות שכדאי לבצע כדי להבטיח שבקשות ברשת יהיו מהירות ויעילות ככל האפשר.

הערכים הבאים של 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 היא הגישה המומלצת כי היא מדויקת יותר.

דוגמה ל-ETag

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

הגדרה של ETag או Last-Modified משפרת מאוד את היעילות של בקשת האימות מחדש. בסופו של דבר, הן מקפיצות את כותרות הבקשות If-Modified-Since או If-None-Match שצוינו בקטע Request header.

כששרת אינטרנט שהוגדר כראוי רואה את הכותרות של הבקשות הנכנסות, הוא יכול לוודא שגרסת המשאב שכבר קיימת במטמון HTTP במטמון תואמת לגרסה האחרונה בשרת האינטרנט. אם יש התאמה, השרת יוכל להגיב בתגובת HTTP מסוג 304 Not Modified, המקבילה ל-"Ok, continue using what you already have already got" (היי, המשיכו להשתמש במה שכבר יש לכם!) כששולחים תשובה מהסוג הזה יש מעט מאוד נתונים, כך שלרוב התהליך הרבה יותר מהיר מאשר לשלוח בחזרה עותק של המשאב המבוקש.

תרשים של לקוח שמבקש משאב והשרת שמגיב עם כותרת 304.
הדפדפן מבקש /file מהשרת וכולל את הכותרת If-None-Match, שמנחה את השרת להחזיר את הקובץ המלא רק אם ETag של הקובץ בשרת לא תואם לערך If-None-Match של הדפדפן. במקרה זה, שני הערכים לא היו תואמים, לכן השרת החזיר תגובה 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 הסבר
max-age=86400 דפדפנים ומטמון ביניים יכולים לשמור את התגובה במטמון למשך עד יום אחד (60 שניות x 60 דקות x 24 שעות).
private, max-age=600 התגובה יכולה להישמר במטמון על ידי הדפדפן (אבל לא מטמון ביניים), למשך עד 10 דקות (60 שניות x 10 דקות).
public, max-age=31536000 ניתן לשמור את התשובה בכל מטמון למשך שנה.
no-store לא ניתן לשמור את התגובה במטמון ויש לאחזר אותה במלואה בכל בקשה.