ربما أجريت اختبار سرعة، وشاهدت تحذيرًا بخصوص "الاستفادة من التخزين المؤقت للمتصفح"، وأغلقت الصفحة من الحيرة. هذا مفهوم تمامًا. رؤوس التخزين المؤقت تبدو كشيء يجب أن يتعامل معه مهندسو الباك اند فقط. لكن بعد فهم الفكرة الأساسية، الأمر بسيط جدًا في الواقع، وإصلاحه يمكن أن يوفر وقتًا حقيقيًا في كل زيارة متكررة لموقعك.
لنحلل ما تفعله هذه الرؤوس بالضبط، وأيها المهم، وكيف تُهيّئها دون كسر أي شيء.
ماذا تفعل رؤوس التخزين المؤقت للمتصفح بالفعل
في كل مرة يزور فيها شخص موقعك، يقوم متصفحه بتنزيل مجموعة من الملفات: شعارك، ورقة الأنماط (stylesheet)، حزم JavaScript، وربما خط أو اثنين. بدون تعليمات تخزين مؤقت، يتعين على المتصفح تنزيل كل ذلك مرة أخرى في الزيارة التالية، حتى لو لم يتغير شيء.
رؤوس التخزين المؤقت هي تعليمات يرسلها خادمك مع كل ملف، تقول للمتصفح: "اسمع، يمكنك الاحتفاظ بهذا لفترة. لا حاجة لطلبه مني مرة أخرى." هذه هي الفكرة كلها. التعقيد يأتي من اختيار التعليمات الصحيحة لكل نوع من الملفات.
الرأسان الأهم
هناك عدد من رؤوس HTTP المعنية، لكن اثنين منها يقومان بمعظم العمل:
- Cache-Control - يخبر المتصفح كم من الوقت يجب تخزين الملف وتحت أي شروط
- ETag - بصمة لمحتوى الملف، تُستخدم للتحقق مما إذا تغير دون إعادة تنزيله
ستجد أيضًا Expires في الإعدادات القديمة، لكن Cache-Control حل محله إلى حد كبير لأنه أكثر مرونة.
إعداد تخزين مؤقت للسيرفر عملي
هذه نقطة انطلاق واقعية لإعداد التخزين المؤقت للسيرفر يمكن لمعظم المواقع استخدامها دون مشاكل. هذا المثال مكتوب لـ Nginx، لكن المنطق ينطبق في كل مكان.
location ~* \.(jpg|jpeg|png|webp|gif|svg|woff2|woff)$ { expires 30d; add_header Cache-Control "public, immutable"; } location ~* \.(css|js)$ { expires 7d; add_header Cache-Control "public"; } location ~* \.(html)$ { add_header Cache-Control "no-cache"; }لاحظ النمط: الصور والخطوط تحصل على مدد تخزين طويلة لأنها نادرًا ما تتغير. CSS و JS يحصلان على فترة أقصر لأنهما يتحدثان بشكل أكثر تكرارًا خلال التطوير النشط. HTML يحصل على تخزين مؤقت قليل جدًا أو معدوم، لأنك تريد أن يحصل الزوار دائمًا على أحدث نسخة من بنية الصفحة نفسها.
لماذا يهم "immutable"
توجيه immutable يخبر المتصفح بألا يزعج نفسه حتى بالتحقق من تغيّر الملف حتى ينتهي وقت التخزين المؤقت. هذا يتجاوز رحلة شبكة صغيرة لكنها حقيقية تُسمى "طلب إعادة التحقق". بالنسبة للملفات التي تحمل تجزئات إصدار (hash) في اسمها (مثل app.a3f8c1.js)، هذا أمر آمن تمامًا، لأن أي تغيير في المحتوى ينتج عنه دائمًا اسم ملف جديد.
حيلة تجزئة اسم الملف
هذا هو الجزء الذي يفوّته الكثيرون. مدد التخزين المؤقت الطويلة تعمل بشكل جيد فقط إذا كانت عملية البناء (build) لديك تغيّر اسم الملف كل مرة يتغير فيها المحتوى. معظم أدوات التجميع الحديثة (Webpack، Vite، esbuild) تفعل ذلك تلقائيًا، بإضافة تجزئة مثل -8f92ab إلى اسم الملف.
بدون هذا، عليك الاختيار بين خيارين سيئين: تخزين مؤقت بقوة مع خطر أن يرى الزوار CSS قديمًا معطلًا، أو تخزين مؤقت بالحد الأدنى وفقدان فائدة الأداء بالكامل. مع أسماء الملفات المُجزّأة، تحصل على الأفضل من الأمرين. خزّن للأبد، وفي اللحظة التي يتغير فيها المحتوى، يتغير الرابط أيضًا، فيضطر المتصفح لجلب النسخة الجديدة.
قياس الأثر الحقيقي
إعداد التخزين المؤقت للسيرفر الجيد يظهر بوضوح في بعض المقاييس:
- زمن تحميل الزيارة المتكررة - يجب أن ينخفض بشكل كبير، غالبًا بنسبة 40-70% أسرع من الزيارة الأولى
- إجمالي البيانات المنقولة - تحقق من ذلك في تبويب Network في Chrome DevTools عند تحميل الصفحة ثانية؛ الملفات المخزنة مؤقتًا تظهر "(disk cache)" أو "(memory cache)" بدلًا من حجم نقل
- وقت التفاعل (Time to Interactive) - يتحسن لأن المتصفح يتجاوز التنزيلات المكررة ويحلل JS المخزن مؤقتًا بشكل أسرع
يمكنك التحقق من أن رؤوسك تعمل فعليًا بفتح DevTools، والانتقال إلى تبويب Network، وإعادة تحميل الصفحة. اضغط على أي ملف ثابت وتحقق من قسم Response Headers للبحث عن Cache-Control. إذا كان غائبًا تمامًا، فإن خادمك لا يرسل أي تعليمات تخزين مؤقت على الإطلاق، وكل زيارة تتصرف كأنها زيارة أولى.
أخطاء شائعة تُفسد إعداد التخزين المؤقت للسيرفر
تخزين HTML مؤقتًا بشكل مفرط
إذا خزّنت صفحات HTML الفعلية لأيام، فقد لا يرى الزوار تحديثات المحتوى، أو تغييرات الأسعار، أو مقالات جديدة لفترة طويلة. حافظ على سياسات قصيرة أو بلا تخزين مؤقت لـ HTML، واترك الملفات الثابتة تحمل مدد التخزين الطويلة.
نسيان معاملات الاستعلام (Query Strings)
بعض الإعدادات القديمة تستخدم style.css?v=2 لفرض إبطال التخزين المؤقت. هذا يعمل، لكنه أقل موثوقية عبر CDN والبروكسيات من التجزئة الفعلية لاسم الملف. إذا استطعت التحول إلى أسماء ملفات مُجزّأة، فافعل ذلك.
عدم وجود رؤوس تخزين مؤقت على استجابات API
الملفات الثابتة ليست الشيء الوحيد الذي يستفيد. إذا كانت لديك نقاط API تُرجع بيانات نادرًا ما تتغير، مثل قائمة بلدان أو فئات، فإن Cache-Control: public, max-age=300 قصيرة يمكن أن تقلل من الحمل على الخادم بشكل ملحوظ دون أي خطر لمشاكل البيانات القديمة.
أين يتناسب التخزين المؤقت من جهة السيرفر
التخزين المؤقت للمتصفح يتعامل مع الزيارات المتكررة من نفس الشخص. لكن معظم زوارك هم زوار جدد لأول مرة، وهناك يقوم التخزين المؤقت من جهة السيرفر (تخزين الصفحة، تخزين الكائنات، تخزين CDN) بالعمل الأساسي. تناولنا الجانب الخاص بالسيرفر من هذا في كيفية إعداد تخزين Redis المؤقت على خادمك دون كسر أي شيء و Memcached مقابل Redis: أي طبقة تخزين مؤقت تناسب خادمك، إذا أردت التعمق أكثر في هذا الجانب من المنظومة.
إذا كنت تستخدم WordPress، فإن كثيرًا من هذا يتم التعامل معه تلقائيًا بمجرد تفعيل الإعدادات الصحيحة. التخزين المؤقت على مستوى الصفحة، وتحسين الملفات، وحتى التخزين المؤقت للكائنات المبني على Redis لاستعلامات قاعدة البيانات، كل ذلك يمكن أن يعمل دون أن تلمس ملف إعدادات مباشرة، وهذا جدير بالمعرفة إذا كنت تفضل قضاء وقتك في المحتوى بدلًا من إعدادات الخادم. يمكنك قراءة المزيد عن التخزين المؤقت للسيرفر و تخزين Redis المؤقت إذا كان هذا هو المسار الذي تريد اتباعه.
خلاصة بسيطة
رؤوس التخزين المؤقت للمتصفح ليست معقدة بمجرد أن ترى النمط: خزّن الملفات الثابتة المُجزّأة بقوة، حافظ على HTML طازجًا، وتحقق من أن الأمر يعمل فعليًا في DevTools بدلًا من الافتراض. افعل ذلك، وسيلاحظ زوارك العائدون الفرق فورًا، حتى لو لم يستطيعوا إخبارك بالسبب.