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

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

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

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

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

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

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

Cache-Control

دعم المتصفح

  • صحيح
  • 12
  • صحيح
  • صحيح

المصدر

ETag

دعم المتصفح

  • صحيح
  • 12
  • صحيح
  • صحيح

المصدر

Last-Modified

دعم المتصفح

  • صحيح
  • 12
  • صحيح
  • صحيح

المصدر

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

عندما يلاحظ خادم ويب مهيأ بشكل صحيح رؤوس الطلبات الواردة هذه، يمكنه تأكيد ما إذا كان إصدار المورد الموجود في المتصفح من قبل في ذاكرة التخزين المؤقت لـ 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، يمكنك الاطّلاع على دليل أفضل ممارسات التخزين المؤقت وحلول الحدّ الأقصى للسن المسموح به من "جيك أرشيبالد".

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

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

إذا كان لديك متسع من الوقت، فإليك بعض الطرق التي يمكنك من خلالها تحسين استخدامك لذاكرة التخزين المؤقت لـ 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 لا يُسمح بتخزين الاستجابة مؤقتًا ويجب استرجاعها بالكامل في كل طلب.