منع الطلبات غير الضرورية من الشبكة باستخدام ذاكرة التخزين المؤقت عبر HTTP

إنّ جلب الموارد عبر الشبكة بطيء ومكلف:

  • تتطلّب الردود الكبيرة العديد من عمليات الإرسال والاستقبال بين المتصفّح والخادم.
  • لن يتم تحميل صفحتك إلى أن يتم تنزيل جميع الموارد المهمة بالكامل.
  • إذا كان أحد المستخدمين يصل إلى موقعك الإلكتروني باستخدام خطة بيانات جوّال محدودة، فإنّ كل طلب شبكة غير ضروري يُعدّ إهدارًا لأمواله.

كيف يمكنك تجنُّب طلبات الشبكة غير الضرورية؟ ذاكرة التخزين المؤقت لبروتوكول HTTP في المتصفّح هي خط الدفاع الأول. وهو ليس بالضرورة الأسلوب الأكثر فعالية أو مرونة، ولديك تحكّم محدود في مدة صلاحية الردود المخزّنة مؤقتًا، ولكنه فعّال ومتوافق مع جميع المتصفّحات ولا يتطلّب الكثير من العمل.

يوضّح لك هذا الدليل أساسيات تنفيذ التخزين المؤقت لبروتوكول HTTP بشكل فعّال.

توافُق المتصفح

لا تتوفّر في الواقع واجهة برمجة تطبيقات واحدة تُعرف باسم "ذاكرة التخزين المؤقت لبروتوكول HTTP". وهو الاسم العام لمجموعة من واجهات برمجة التطبيقات لمنصات الويب. تتوفّر واجهات برمجة التطبيقات هذه في جميع المتصفّحات:

Cache-Control

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

ETag

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Last-Modified

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

طريقة عمل ذاكرة التخزين المؤقت على الويب

يتم أولاً توجيه جميع طلبات HTTP التي يرسلها المتصفّح إلى ذاكرة التخزين المؤقت في المتصفّح للتحقّق مما إذا كانت هناك استجابة صالحة مخزّنة مؤقتًا يمكن استخدامها لتلبية الطلب. إذا كان هناك تطابق، تتم قراءة الاستجابة من ذاكرة التخزين المؤقت، ما يزيل كلاً من وقت استجابة الشبكة وتكاليف البيانات التي تتكبدها عملية النقل.

يتم التحكّم في سلوك ذاكرة التخزين المؤقت عبر HTTP من خلال مجموعة من عناوين الطلبات وعناوين الاستجابات. في السيناريو المثالي، سيكون لديك إمكانية التحكّم في كلّ من الرمز البرمجي لتطبيق الويب (الذي سيحدّد عناوين الطلبات) وإعدادات خادم الويب (التي ستحدّد عناوين الاستجابة).

يمكنك الرجوع إلى مقالة التخزين المؤقت لبروتوكول HTTP في شبكة مطوّري برامج Mozilla (MDN) للحصول على نظرة عامة أكثر تفصيلاً حول هذا المفهوم.

عناوين الطلبات: الالتزام بالإعدادات التلقائية (عادةً)

هناك عدد من العناوين المهمة التي يجب تضمينها في الطلبات الصادرة من تطبيق الويب، ولكن المتصفّح يتولّى دائمًا ضبطها نيابةً عنك عند إرسال الطلبات. تظهر عناوين الطلبات التي تؤثر في التحقّق من حداثة المحتوى، مثل If-None-Match وIf-Modified-Since، استنادًا إلى فهم المتصفّح للقيم الحالية في ذاكرة التخزين المؤقت عبر HTTP.

هذا خبر سار، ويعني أنّه يمكنك مواصلة تضمين علامات مثل <img src="my-image.png"> في ترميز HTML، وسيتولى المتصفّح تلقائيًا معالجة التخزين المؤقت لبروتوكول 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، أتمتة عملية تخصيص بصمات التجزئة لعناوين URL الخاصة بمواد العرض.

إعادة التحقّق من الخادم لعناوين URL التي لا تتضمّن إصدارات

للأسف، لا يتم تحديد إصدارات لجميع عناوين URL التي تحمّلها. قد لا تتمكّن من تضمين خطوة إنشاء قبل نشر تطبيق الويب، لذا لا يمكنك إضافة تجزئات إلى عناوين URL لمواد العرض. ويحتاج كل تطبيق ويب إلى ملفات HTML، ولن تتضمّن هذه الملفات (تقريبًا) معلومات الإصدارات، لأنّه لن يكلّف أحد نفسه عناء استخدام تطبيق الويب إذا كان عليه تذكُّر أنّ عنوان URL الذي يجب زيارته هو https://example.com/index.34def12.html. إذًا، ما الذي يمكنك فعله بشأن عناوين URL هذه؟

هذا سيناريو واحد تحتاج فيه إلى الاعتراف بالهزيمة. لا يكفي التخزين المؤقت عبر HTTP وحده لتجنّب الشبكة تمامًا. (لا داعي للقلق، ستتعرّف قريبًا على مشغّلي الخدمات الذين سيقدّمون الدعم اللازم لكسب المعركة لصالحك). ولكن هناك بعض الخطوات التي يمكنك اتّخاذها للتأكّد من أنّ طلبات الشبكة سريعة وفعّالة قدر الإمكان.

يمكن أن تساعدك قيم Cache-Control التالية في ضبط مكان وكيفية تخزين عناوين URL غير المحدّدة الإصدار مؤقتًا:

  • no-cache. يوجّه ذلك المتصفّح إلى أنّه يجب إعادة التحقّق من الخادم في كل مرة قبل استخدام نسخة مخزّنة مؤقتًا من عنوان URL.
  • no-store: يوجّه هذا الإعداد المتصفّح وذاكرات التخزين المؤقت الوسيطة الأخرى (مثل شبكات توصيل المحتوى) إلى عدم تخزين أي نسخة من الملف مطلقًا.
  • ‫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 المذكورة في عناوين الطلبات.

عندما يرى خادم ويب تم ضبطه بشكل صحيح عناوين الطلبات الواردة هذه، يمكنه التأكّد مما إذا كان إصدار المورد الذي يتوفّر لدى المتصفّح في ذاكرة التخزين المؤقت لبروتوكول HTTP يتطابق مع أحدث إصدار على خادم الويب. إذا كانت هناك مطابقة، يمكن للخادم الردّ باستجابة HTTP‏ 304 Not Modified، ما يعني "يمكنك مواصلة استخدام ما لديك". لا يتطلّب إرسال هذا النوع من الاستجابة نقل الكثير من البيانات، لذا يكون عادةً أسرع بكثير من إرسال نسخة من المورد الفعلي المطلوب.

رسم توضيحي لعميل يطلب موردًا والخادم يستجيب برأس 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، يمكنك مراجعة دليل جيك أرشيبالد حول أفضل ممارسات التخزين المؤقت ومشاكل max-age.

راجِع مقالة الاستفادة من ذاكرة التخزين المؤقت للحصول على إرشادات حول كيفية تحسين استخدام ذاكرة التخزين المؤقت للزوّار المتكرّرين.

الملحق: مزيد من النصائح

إذا كان لديك المزيد من الوقت، إليك طرق أخرى يمكنك من خلالها تحسين استخدامك لذاكرة التخزين المؤقت لبروتوكول HTTP:

  • استخدِم عناوين URL متسقة، فإذا كنت تعرض المحتوى نفسه على عناوين URL مختلفة، سيتم جلب هذا المحتوى وتخزينه عدة مرات.
  • الحدّ من إيقاف الاستخدام إذا كان جزء من مورد (مثل ملف CSS) يتم تعديله بشكل متكرر، في حين أنّ بقية الملف لا يتم تعديلها (مثل رمز المكتبة)، ننصحك بتقسيم الرمز الذي يتم تعديله بشكل متكرر إلى ملف منفصل واستخدام استراتيجية تخزين مؤقت قصيرة المدة للرمز الذي يتم تعديله بشكل متكرر واستراتيجية تخزين مؤقت طويلة المدة للرمز الذي لا يتغير كثيرًا.
  • اطّلِع على توجيه stale-while-revalidate الجديد إذا كان من المقبول أن تكون سياسة Cache-Control قديمة إلى حدّ ما.

الملحق: المخطط الانسيابي لـ "Cache-Control"

المخطط الانسيابي
عملية اتخاذ القرار لضبط عناوين Cache-Control.

الملحق: أمثلة على Cache-Control

قيمة Cache-Control الشرح
max-age=86400 يمكن تخزين الاستجابة مؤقتًا من خلال المتصفحات وذاكرات التخزين المؤقت الوسيطة لمدة تصل إلى يوم واحد (60 ثانية × 60 دقيقة × 24 ساعة).
private, max-age=600 يمكن للمتصفّح تخزين الاستجابة مؤقتًا (ولكن ليس في ذاكرة التخزين المؤقت الوسيطة) لمدة تصل إلى 10 دقائق (60 ثانية × 10 دقائق).
public, max-age=31536000 يمكن تخزين الاستجابة في أي ذاكرة تخزين مؤقت لمدة عام واحد.
no-store لا يُسمح بتخزين الاستجابة مؤقتًا ويجب جلبها بالكامل في كل طلب.