المستوى: مبتدئ
لو موقعك بيحمّل نفس logo.png و main.css في كل صفحة جديدة، أنت بتدفع ثمن نقل بيانات مفيش لازمة له. ضبط Cache-Control بسطر واحد بيخلّي المتصفح يحتفظ بالملفات دي محلياً ويوفّر 87% من عدد الطلبات بدون ما تلمس الكود.
HTTP Cache-Control: لغة الاتفاق بين السيرفر والمتصفح
المشكلة باختصار
كل ما زائر يفتح صفحة على موقعك، المتصفح بيتصل بالسيرفر ويطلب كل ملف من الأول: HTML، CSS، JavaScript، صور، خطوط. لو نفس الزائر فتح 5 صفحات في زيارة واحدة، السيرفر بعت نفس logo.png 5 مرات. الـ bandwidth ضاع، السيرفر اتشغل غصب عنه، والمستخدم استنى أطول.
السبب مش الكود ولا السيرفر بطيء. السبب إن المتصفح مش عارف هل ينفع يحتفظ بالملف ولا لازم يطلبه تاني. اللي بيقوله للمتصفح هو header اسمه Cache-Control.
مثال بسيط للمبتدئ: المكتبة العامة
تخيّل إنك بتروح مكتبة عامة كل يوم وبتقرأ نفس الكتاب. لو كل مرة بتطلبه من أمين المكتبة وتستنى دقيقة لحد ما يجيبه من المخزن، ده هدر وقت. الحل إنك تاخد نسخة منه البيت لمدة شهر. خلال الشهر ده، تقدر تقراه وقت ما تحب من غير ما تعدي على المكتبة. لو الكتاب اتغيّر، أمين المكتبة بيقولك: "في طبعة جديدة، تعالى خد نسخة جديدة".
المتصفح هو القارئ. السيرفر هو أمين المكتبة. الملف هو الكتاب. Cache-Control هو الورقة اللي السيرفر بيلصقها على كل ملف ويقول للمتصفح فيها بالظبط: "احتفظ بده عندك مدة كذا، ومتسألنيش عنه تاني خلال المدة دي".
تعريف Cache-Control بدقة
Cache-Control هو HTTP response header بيتحط من السيرفر مع كل response. هو بيتحكم في سلوك أي cache بين السيرفر والمستخدم: cache المتصفح المحلي، الـ CDN، والـ proxy. أهم الـ directives اللي تحتاجها:
max-age=N: المتصفح يحتفظ بالملف N ثانية. خلالها مش هيبعت طلب أصلاً للسيرفر.public: ينفع يتعمله cache على CDN ومشترك بين مستخدمين.private: cache في متصفح المستخدم فقط، ممنوع على CDN. مفيد للملفات اللي فيها بيانات شخصية.no-store: ممنوع cache نهائي. لأي response فيه بيانات حساسة (مثل response خاص بحساب بنكي).immutable: الملف ده مش هيتغيّر أبداً. المتصفح حتى مش هيتحقق منه عند الـ Refresh العادي.must-revalidate: لما الـmax-ageتخلص، اسأل السيرفر قبل ما تستخدم النسخة المحلية.
الإعداد العملي على NGINX
زوّد البلوك ده في server config:
# الملفات المهيشّت بإصدار في اسمها (main.a3f9c1.css)
# آمن إنها تتخزن سنة كاملة لإن أي تغيير = اسم جديد
location ~* \.(css|js|woff2|jpg|png|webp|avif|svg)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
}
# HTML لازم يتفحص في كل request
# لإنه هو اللي بيشاور على الإصدارات الجديدة من باقي الأصول
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, must-revalidate";
}
# API responses: مفيش cache
location /api/ {
add_header Cache-Control "no-store";
}