ضبط سلوك تخزين HTTP

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

التعرّف على المشروع النموذجي

في ما يلي الملفات الرئيسية التي ستعمل عليها في المشروع النموذجي:

  • يحتوي الملف server.js على رمز Node.js الذي يعرض محتوى تطبيق الويب. ويستخدم Express لمعالجة طلبات HTTP والاستجابات. على وجه الخصوص، يتم استخدام express.static() لعرض جميع الملفات المحلية في الدليل العام، لذا فإنّ serve-static الوثائق ستكون مفيدة.
  • ‫public/index.html هو رمز HTML لتطبيق الويب. مثل معظم ملفات HTML، لا يحتوي على أي معلومات حول الإصدار كجزء من عنوان URL الخاص به.
  • ‫public/app.15261a07.js وpublic/style.391484cf.css هما مواد عرض JavaScript وCSS لتطبيق الويب. يحتوي كل ملف من هذه الملفات على تجزئة في عناوين URL الخاصة بها، المقابلة لمحتوياتها. يكون index.html مسؤولاً عن تتبُّع عنوان URL المحدّد الذي يتضمّن الإصدار المطلوب تحميله.

ضبط عناوين التخزين المؤقت لملفات HTML

عند الردّ على طلبات عناوين URL التي لا تحتوي على معلومات حول الإصدار، تأكَّد من إضافة Cache-Control: no-cache إلى رسائل الردّ. بالإضافة إلى ذلك، ننصحك بضبط أحد عنوانَي الاستجابة الإضافيَّين: إما Last-Modified أو ETag. يندرج index.html ضمن هذه الفئة. يمكنك تقسيم ذلك إلى خطوتين.

أولاً، يتم التحكّم في الرأسَين Last-Modified وETag من خلال خيارَي الضبط etag وlastModified. يتم ضبط كلا الخيارَين تلقائيًا على true لجميع استجابات HTTP، لذا في هذا الإعداد الحالي، ليس عليك الموافقة للحصول على هذا السلوك. ومع ذلك، يمكنك تحديد ذلك في الإعدادات.

ثانيًا، يجب أن تكون قادرًا على إضافة عنوان Cache-Control: no-cache، ولكن فقط لمستندات HTML (index.html، في هذه الحالة). أسهل طريقة لضبط هذا العنوان بشكل مشروط هي كتابة setHeaders function مخصّصة، والتحقّق من خلالها مما إذا كان الطلب الوارد مخصّصًا لمستند HTML.

يبدأ إعداد العرض الثابت في server.js على النحو التالي:

app.use(express.static('public'));
  • أجرِ التغييرات الموضّحة أعلاه، وستحصل على نتيجة تشبه ما يلي:
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    }
  },
}));

ضبط عناوين التخزين المؤقت لعناوين URL التي تتضمّن إصدارات

عند الردّ على طلبات عناوين URL التي تحتوي على معلومات "بصمة الإصبع" أو معلومات الإصدارات، والتي لا يُفترض أن يتغيّر محتواها أبدًا، أضِف Cache-Control: max-age=31536000 إلى ردودك. ويندرج app.15261a07.js وstyle.391484cf.css ضمن هذه الفئة.

استنادًا إلى setHeaders function المستخدَم في الخطوة الأخيرة، يمكنك إضافة منطق إضافي للتحقّق مما إذا كان الطلب المحدّد مخصّصًا لعنوان URL يتضمّن إصدارًا، وإذا كان الأمر كذلك، يمكنك إضافة العنوان Cache-Control: max-age=31536000.

وأفضل طريقة لإجراء ذلك هي استخدام تعبير عادي لمعرفة ما إذا كان الملف المطلوب يتطابق مع نمط معيّن تعرف أنّ تجزئات الملفات تندرج ضمنه. في حالة نموذج المشروع هذا، يكون دائمًا ثمانية أحرف من مجموعة الأرقام من 0 إلى 9 والأحرف الصغيرة من a إلى f (أي أحرف نظام العد الستة عشري). ويتم دائمًا فصل علامة التجزئة باستخدام الرمز . على أي من الجانبين.

يمكن التعبير عن التعبير العادي الذي يطابق هذه القواعد العامة على النحو التالي: new RegExp('\\.[0-9a-f]{8}\\.').

  • عدِّل الدالة setHeaders لتصبح على النحو التالي:
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    const hashRegExp = new RegExp('\\.[0-9a-f]{8}\\.');

    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    } else if (hashRegExp.test(path)) {
      // If the RegExp matched, then we have a versioned URL.
      res.setHeader('Cache-Control', 'max-age=31536000');
    }
  },
}));

تأكيد السلوك الجديد باستخدام "أدوات مطوّري البرامج"

بعد إجراء التعديلات على خادم الملفات الثابتة، يمكنك التحقّق من ضبط العناوين الصحيحة من خلال معاينة التطبيق المباشر مع فتح لوحة الشبكة في "أدوات مطوري البرامج".

  • يمكنك تخصيص الأعمدة التي تظهر في لوحة الشبكة لتشمل المعلومات الأكثر صلة، وذلك بالنقر بزر الماوس الأيمن في رأس العمود:

ضبط لوحة "الشبكة" في "أدوات مطوّري البرامج"

الأعمدة التي يجب الانتباه إليها هنا هي Name وStatus وCache-Control وETag وLast-Modified.

  • بعد فتح "أدوات مطوّري البرامج" في لوحة "الشبكة"، أعِد تحميل الصفحة.

بعد تحميل الصفحة، من المفترض أن تظهر لك إدخالات في "لوحة الشبكة" تشبه ما يلي:

أعمدة لوحة الشبكة

الصف الأول مخصّص لمستند HTML الذي انتقلت إليه. يتم تقديم هذا الطبق بشكل صحيح مع Cache-Control: no-cache. حالة استجابة HTTP لهذا الطلب هي 304. يعني ذلك أنّ المتصفّح لم يستخدم ملف HTML المخزَّن مؤقتًا على الفور، بل أرسل طلب HTTP إلى خادم الويب باستخدام معلومات Last-Modified وETag لمعرفة ما إذا كان هناك أي تعديل على ملف HTML المخزَّن مؤقتًا. تشير استجابة HTTP 304 إلى عدم توفّر HTML معدَّل.

الصفان التاليان مخصّصان لمواد عرض JavaScript وCSS التي تم إصدارها. من المفترض أن تظهر لك هذه الصفحات معروضة باستخدام Cache-Control: max-age=31536000، وأن تكون حالة HTTP لكل منها 200. بسبب الإعدادات المستخدَمة، لا يتم إرسال أي طلب فعلي إلى خادم Node.js، وسيؤدي النقر على الإدخال إلى عرض تفاصيل إضافية، بما في ذلك أنّ الاستجابة جاءت "(من ذاكرة التخزين المؤقت للقرص)".

حالة استجابة الشبكة 200

لا تهمّ كثيرًا القيم الفعلية لعمودَي ETag وLast-Modified. المهم هو التأكد من ضبطها.

تلخيص الأمور

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