منع الطلبات غير الضرورية من الشبكة باستخدام ذاكرة التخزين المؤقت عبر 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 في 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 التي تتضمّن نُسخًا

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

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

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