لنفترض أنك عدّلت ساعات عمل اليوم في موقع مكتبة، لكن بعض الزوار ما زالوا يرون الموعد القديم. ينبغي أولاً التمييز بين عدم تحديث الأصل في الخادم، وإعادة المتصفح استخدام استجابة محفوظة، وتقديم خادم وسيط نسخة أقدم. مجرد إعادة تحميل الصفحة مرات كثيرة لا يبيّن وحده المرحلة التي سببت المشكلة.
تحفظ ذاكرة HTTP المؤقتة الاستجابات المستلمة وتعيد استخدامها عند تحقق الشروط. يربط هذا المقال تعليمات التخزين والتحقق في Cache-Control مع ETag واستجابات 304، عبر حالة افتراضية لجدول ساعات متاح للجميع. سجلات التبادل التالية مختصرة للتوضيح، وليست قياسات لمكتبة حقيقية أو خادم معيّن. الهدف هو شرح أي استجابة يجوز استخدامها مجدداً ومتى، بدلاً من وصفة لإزالة جميع النسخ المؤقتة.
1. هل نخزّن الاستجابة، ومتى نتحقق منها، ومع مَن نشاركها؟
عند قراءة سياسة التخزين، دوّن ثلاثة أسئلة منفصلة: هل يجوز حفظ الاستجابة، وهل يجوز استخدام النسخة المحفوظة مباشرة للطلب التالي، وهل يجوز مشاركتها بين عدة مستخدمين؟ السماح بالتخزين لا يعني السماح بإعادة الاستخدام دائماً، والتحقق من حداثة المحتوى لا يبيح مشاركته مع الآخرين. يعرّف معيار HTTP للتخزين المؤقت RFC 9111 هذه الشروط بتوجيهات منفصلة. نتناول هنا توجيهات الاستجابة التي لا تُضاف إليها أسماء حقول كوسائط مستقلة.
| السؤال المطلوب حسمه | توجيه الاستجابة | المعنى الذي يجب تمييزه |
|---|---|---|
| هل يُمنع تخزين الاستجابة؟ | no-store | توجيه يمنع حفظها لإعادة استخدامها لاحقاً |
| هل يلزم التحقق قبل إعادة الاستخدام؟ | no-cache | يمكن حفظها، لكن يلزم تحقق ناجح قبل إعادة الاستخدام |
| هل يمكن مشاركتها بين المستخدمين؟ | private | يمنع حفظها في ذاكرة مشتركة، ولا يمنع كل حفظ في ذاكرة خاصة |
مثلاً، إذا كان جدول الساعات العام يتغير كثيراً في العنوان نفسه، يمكنك دراسة اشتراط التحقق قبل الاستخدام حتى مع وجود نسخة محفوظة. أما الشاشات المخصصة للأفراد فتختلف عن الجدول العام منذ شروط المشاركة نفسها. يتعلق private بذاكرة التخزين المشتركة، ولا يحل محل تسجيل الدخول وفحص الصلاحيات. جمع إعدادات ذات أغراض مختلفة في عبارة واحدة قد يغيّر الجمهور الذي يتلقى المعلومات خطأً أثناء محاولة تسريعها.
لا تضع التوجيه فقط في جدول السياسة، بل أضف سببه أيضاً: هل الجدول معلومات عامة تحتاج إلى فحص التغييرات؟ هل الشعار ملف ثابت المحتوى؟ هل يقدّم العنوان نفسه معلومات شخصية؟ هذا الجدول نقطة بداية لتصنيف الاستجابات الفعلية، وليس إعداداً مكتملاً يصلح لكل المواقع. وينبغي أيضاً تحديد المخزن المقصود، مثل المتصفح أو CDN.
2. لا تختر no-cache وno-store بناءً على الاسم وحده
يسهل فهم اسم no-cache على أنه منع للتخزين، لكن معناه في الاستجابة هو التحقق من النسخة المحفوظة قبل إعادة استخدامها. إذا أكد الخادم عدم التغيير، فقد يُستخدم المتن المحفوظ مجدداً. أما no-store فهو توجيه بعدم حفظ هذه الاستجابة. لأن ما يُحفظ وما يُفحص في الطلب التالي مختلفان، فلا تتوقع السلوك نفسه من الإعدادين.
تعني fresh في سياق الذاكرة المؤقتة أن السياسة تسمح بإعادة الاستخدام دون تحقق إضافي. ولا تضمن أن المشغّل لم يغيّر المحتوى في الأثناء. إذا حُددت مدة الاستخدام بـmax-age، فقد يستمر اختيار الاستجابة المحفوظة حتى إن تغيّر الأصل خلالها. حدّد أولاً تأخر التحديث المقبول، ثم اربط المطلب بالتوجيه. لا تنسخ مدة حفظ طويلة اعتباطية على أنها الحل الصحيح لتحسين الأداء.
يوضح دليل MDN للتخزين المؤقت في HTTP أن إضافة no-store إلى استجابة جديدة لا تحذف الاستجابة القديمة المحفوظة للعنوان نفسه. وإذا ظلت النسخة القديمة صالحة ولم يُطلب جواب جديد، فقد لا يصل الرأس الجديد أصلاً. لا تعتبر no-store أمراً لمسح كل الذاكرة المؤقتة أو شرطاً كافياً لحماية الخصوصية؛ افحص عمر الاستجابات الموجودة وآلية تحديث المخازن التي يمكنك إدارتها.
3. تتبّع زيارة متكررة باستخدام ETag و304
لنفترض أن عنوان الجدول الافتراضي /hours.json يُعلن أولاً إغلاق المكتبة في 18:00. يعرض المثال التالي صيغة HTTP/1.1 تعليمية مع الأجزاء الضرورية فقط، وقد حُذفت الرؤوس الأخرى المطلوبة في استجابة فعلية. hours-v1 معرّف للتمثيل اختاره الخادم في المثال، وليس معادلة لحساب الوقت ولا بصمة حقيقية لملف.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache
ETag: "hours-v1"
{"closes":"18:00"}
إذا حفظ المتصفح هذه الاستجابة، فيمكنه لاحقاً إرسال قيمة ETag في رأس If-None-Match ضمن طلب مشروط. عندما يرى الخادم أن الشرط يطابق التمثيل الحالي المختار وأنه لم يتغير، يرد بـ304 Not Modified. الكتلة التالية سجل مختصر يضع الطلب والاستجابة متتاليين. وليست مثالاً على إرسال متن JSON للجدول من جديد بعد 304.
GET /hours.json HTTP/1.1
Host: library.example
If-None-Match: "hours-v1"
HTTP/1.1 304 Not Modified
Cache-Control: no-cache
ETag: "hours-v1"
كما يوضح شرح MDN لرأس ETag، يستخدم العميل المتن المحفوظ في هذه الحالة. لا تحتوي 304 على متن جديد، لكن إرسال الطلب والتحقق ما زالا يتطلبان اتصالاً. إذا تغيّر موعد الإغلاق إلى 19:00 وتغيّر تمثيل الخادم أيضاً، فقد نتوقع استجابة 200 بمتن ومعرّف جديدين للشرط القديم. استخدام no-cache لا يعني أن الرد سيكون دائماً 304، ولا أنه يلغي استعلام قاعدة البيانات.
المطلوب فحصه هو تطابق المحتوى والمعرّف أكثر من رمز الحالة وحده. إذا تغيّر المحتوى واستمر الخادم باستخدام ETag القديم، فقد تنتج نتيجة تحقق خاطئة. وإذا بقي المحتوى نفسه وتغيّر المعرّف باستمرار، فقد يُرسل المتن مجدداً مرات أكثر. يجب فحص العلاقة بين طريقة توليد المعرّف والتمثيل المختار في الخادم؛ ظهور ETag وحده لا يثبت صحة التنفيذ.
4. ميّز الوثيقة المتغيرة من المورد ذي الاسم الجديد
قد تختلف استراتيجية تحديث وثيقة يتغير محتواها في URL واحد، مثل الجدول، عن شعار أو برنامج نصي يحصل على اسم ملف جديد عند تغيّر المحتوى. إذا انتقل الشعار من logo.a1.png إلى logo.b2.png، فعلى الوثيقة الجديدة أن تشير إلى العنوان الجديد. إضافة معرّف للاسم ثم الكتابة فوق محتوى الملف القديم تخلّ بوعد إدارة المحتوى والعنوان معاً.
رفع ملف جديد لا يعني أن الزائر سيطلب عنوانه الجديد. إذا ظل HTML الذي تلقاه يشير إلى عنوان الشعار القديم، فقد يعاد استخدام المورد القديم. لذلك افحص مسار تحديث الوثيقة التي تشير إلى المورد، لا إعدادات تخزين المورد فقط. بدلاً من وضع مدة حفظ واحدة للوثيقة والمورد، ينبغي تفسير مقدار تأخر التغيير المقبول لكل منهما.
قد تُستخدم الوثائق القديمة والجديدة معاً فترة قصيرة أثناء النشر. نشر الوثيقة قبل جاهزية المورد الجديد أو حذف المورد القديم مبكراً قد يخلق أعطالاً منفصلة. في هذا المثال الافتراضي يمكن التحقق من وجود ملفات الوثيقة الجديدة وإمكانية الوصول إلى ملفات الوثيقة القديمة معاً. تغيير اسم الملف أداة في تصميم التخزين المؤقت، وليس حلاً تلقائياً لكل مسائل ترتيب النشر والتراجع عنه.
5. اختبر فرضية واحدة في كل مرة داخل Network
عند الفحص المباشر، ابدأ بسجل مرجعي في وضع يسمح بالتخزين المؤقت. اقرأ معاً العنوان الكامل ومعاملات الاستعلام، ونسخة الجدول الظاهرة، وحالة الاستجابة، وIf-None-Match في الطلب، وCache-Control وETag في الاستجابة. حتى الرؤوس المتطابقة في الاسم تعبّر عن شروط طرفين مختلفين، لذا دوّن أي جانب تقرأ. يشرح مرجع Chrome DevTools Network كيفية تمييز هذه العناصر ضمن Headers.
| حالة اختبار افتراضية | السجلات التي تُفحص معاً | استنتاج متسرع يجب تجنبه |
|---|---|---|
| طلب الجدول نفسه مجدداً | الطلب المشروط والحالة والوقت الظاهر | بما أن الرد 304 فلم يحدث أي اتصال |
| تعديل الوقت الأصلي ثم الطلب | المتن الجديد وETag والعنوان الفعلي | نجاح الحفظ يعني وصول التحديث إلى الجميع |
| الطلب بعد تعطيل ذاكرة المتصفح | الفرق بين التنزيل الأول والزيارة المعتادة المتكررة | هذه النتيجة هي سرعة الزيارة المتكررة العادية |
| العودة بزر الرجوع | حدوث طلب جديد والشاشة المستعادة | ظهور الشاشة يعني بالضرورة تحقق HTTP جديداً |
بعد ذلك اختبر تعطيل ذاكرة المتصفح كحالة منفصلة. يعمل إعداد Disable cache في Chrome طوال بقاء DevTools مفتوحاً، لذا سجّل حالة فتح الأداة وقيمة الإعداد معاً. يفيد ذلك في دراسة التنزيل الأول، لكنه ليس اختبار كيفية استخدام نسخة محفوظة في زيارة عادية متكررة. إن لم تسجّل تفعيل الإعداد، فقد تظن أن الذاكرة لا تعمل لأنك تتلقى بيانات جديدة دائماً. احتفظ بشروط التجربة كي تعود إلى السماح بالتخزين وتقارن.
يسهل تضييق السبب إن لم تُجرِ تعديلات وطلبات عديدة في الوقت نفسه. افحص أولاً الزيارة المتكررة دون تغيير المحتوى، ثم غيّر بنداً واحداً من الوقت وتابع اختلاف الاستجابة. تغيير عنوان الوثيقة وإعداد الخادم واسم الملف معاً يصعّب معرفة التغيير الذي أحدث النتيجة. إذا لم يظهر 200 أو 304 المتوقع، فاقرأ الطلب والاستجابة الفعليين مجدداً قبل إضافة إعدادات أخرى.
6. افحص مسارات التخزين الأخرى ومعيار الاكتمال
لا تفترض أن تعطيل ذاكرة HTTP في المتصفح يزيل CDN أمام الخادم أو مسارات تخزين التطبيق الأخرى. يمكن فحص ما إذا كان service worker يعالج الطلب، وأي استجابة يختارها الخادم الوسيط، وهل يحتفظ التطبيق بالبيانات السابقة على الشاشة. ظهور URL واحد لا يعني أن الطبقات كلها تستخدم النسخة نفسها.
افصل كذلك الرجوع عن طلب HTTP جديد. حين يستعيد المتصفح شاشة جلسة سابقة، فقد لا يظهر طلب إعادة التحقق المتوقع حتى مع no-cache. اعتبار ذلك فوراً دليلاً على تجاهل الخادم للرأس قد يقود إلى سبب خاطئ. تسجيل حدوث الطلب فعلاً عند انتقال جديد، وإعادة تحميل، ورجوع، كلٌّ على حدة، يمنع جمع ظواهر مختلفة في مشكلة واحدة.
ليس معدل إصابة الذاكرة المؤقتة وحده معيار اكتمال مثال الجدول. افحص استخدام النسخة المحفوظة بصورة صحيحة عندما لا يوجد تغيير، وظهور المعلومات الجديدة خلال التأخر المقبول بعد التعديل، وصحة جمهور مشاركة الاستجابة. توثيق وقت التغيير والملاحظة والشروط والمتن الفعلي يساعد غيرك على إعادة الحالة نفسها. إذا تحسنت أرقام السرعة لكن ساعات العمل الخاطئة ظلت ظاهرة طويلاً، فلم يُحقق المطلب الأصلي.
عند التطبيق في الخدمة الفعلية، راجع سياسة كل نوع استجابة مع إجراء التحديث والتراجع. لا تنسخ تعليمات وثيقة عامة إلى استجابة شخصية، ولا تفسّر نجاح التحقق على أنه إتمام فحص صلاحية الوصول. الرؤوس أدوات تنقل قواعد الحفظ وإعادة الاستخدام. عندما تستطيع شرح ما حُفظ وما مرّ به من فحوص حتى وصل إلى الشاشة الحالية، يصبح تشخيص الصفحة القديمة أدق.