هدر Cache-Control به مرورگر و CDN میگوید هر پاسخ را تا چه مدت و توسط چه کسی میتوان کش کرد. فایلهای استاتیک با نام نسخهدار را با max-age طولانی و immutable کش کنید، HTML را کوتاه یا با اعتبارسنجی مجدد، و صفحههای شخصی مثل پنل کاربری و سبد خرید را با private یا no-store از کش CDN دور نگه دارید. در CDN قانونهای جدا برای مسیرها بسازید و با هدر وضعیت کش، HIT یا MISS بودن را بررسی کنید.
چرا تنظیم کش مهم است؟
CDN فقط وقتی سایت را واقعاً سریع میکند که بداند چه چیزی را میتواند کش کند. اگر هیچ چیز کش نشود، هر درخواست تا سرور اصلی میرود و CDN عملاً فقط یک واسطهٔ اضافه است. اگر بیش از حد کش شود، اتفاق بدتری میافتد: کاربران محتوای قدیمی میبینند، یا در بدترین حالت صفحهٔ شخصی یک کاربر، مثل پنل حساب یا سبد خرید، به کاربر دیگری نشان داده میشود.
ابزار اصلی کنترل این رفتار، هدر HTTP به نام Cache-Control است که سرور در پاسخ هر درخواست میفرستد. مرورگرها و CDNها این هدر را میخوانند و بر اساس آن تصمیم میگیرند. علاوه بر آن، پنل CDN هم معمولاً قانونهایی دارد که میتوانند رفتار هدر را تغییر دهند یا بر آن غلبه کنند. اگر با مفاهیم پایه آشنا نیستید، ابتدا مقالهٔ کش چیست و مقالهٔ CDN چیست را بخوانید.
دستورهای اصلی Cache-Control
هدر Cache-Control از چند دستور تشکیل میشود که با ویرگول از هم جدا میشوند. مهمترینها:
- max-age=N: پاسخ تا N ثانیه تازه است و بدون پرسیدن از سرور قابلاستفاده است.
- s-maxage=N: مثل max-age اما فقط برای کشهای مشترک مثل CDN. به این ترتیب میتوانید به CDN مدت طولانیتری بدهید و به مرورگر مدت کوتاهتر.
- public: پاسخ را هر کشی، از جمله CDN، میتواند ذخیره کند.
- private: فقط مرورگر خود کاربر میتواند ذخیره کند؛ CDN نباید آن را کش کند. برای محتوای شخصی.
- no-cache: برخلاف اسمش، یعنی «ذخیره کن اما پیش از هر استفاده با سرور بررسی کن هنوز معتبر است». این بررسی معمولاً سبک است و اگر چیزی تغییر نکرده باشد، سرور فقط پاسخ کوتاه 304 میفرستد.
- no-store: اصلاً ذخیره نکن؛ برای اطلاعات حساس.
- immutable: محتوا در طول مدت اعتبار هرگز تغییر نمیکند و مرورگر حتی هنگام رفرش هم نیازی به بررسی ندارد.
اشتباه رایج، استفاده از no-cache به جای no-store برای محتوای حساس است. اگر نمیخواهید چیزی هیچجا ذخیره شود، no-store درست است.
راهبرد کش برای انواع محتوا
فایلهای استاتیک با نام نسخهدار. ابزارهای ساخت فرانتاند معمولاً فایلهای CSS و JS را با نامی شامل اثر انگشت محتوا تولید میکنند، مثل app.3f9a2c.js. با هر تغییر، نام فایل عوض میشود. این فایلها را میتوان با خیال راحت برای مدت بسیار طولانی کش کرد:
Cache-Control: public, max-age=31536000, immutable
تصاویر و فونتها بدون نسخه. اگر نام فایل با تغییر محتوا عوض نمیشود، مدت متوسطی مثل یک هفته بدهید تا تغییرات در زمان معقول به کاربران برسد.
صفحههای HTML عمومی. صفحهٔ اصلی، مقالهها و صفحههای محصول برای همه یکساناند و میتوانند در CDN کش شوند، اما چون محتوایشان تغییر میکند، مدت کوتاهتری لازم دارند. یک الگوی خوب، کش کوتاه در مرورگر و کمی طولانیتر در CDN است:
Cache-Control: public, max-age=0, s-maxage=300
صفحههای شخصی و پویا. پنل کاربری، سبد خرید، صفحهٔ پرداخت و هر صفحهای که پس از ورود محتوای متفاوت نشان میدهد هرگز نباید در CDN کش شود:
Cache-Control: private, no-store
API. پاسخهای API معمولاً شخصی یا پرتغییرند و باید no-store یا private باشند، مگر endpointهای عمومی و پرتکرار که با مدت کوتاه قابلکش هستند.
- CSS و JS با نام نسخهدار
- فونتها
- تصاویر محصول و مقاله
- HTML صفحههای عمومی با مدت کوتاه
- پنل کاربری و حساب
- سبد خرید و پرداخت
- پاسخهای API شخصی
- صفحههای مدیریت سایت
تنظیم هدر در Nginx
در Nginx با دستور add_header و بر اساس مسیر یا نوع فایل، هدر مناسب را اضافه کنید:
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(png|jpg|jpeg|webp|svg|woff2)$ {
add_header Cache-Control "public, max-age=604800";
}
location /account/ {
add_header Cache-Control "private, no-store" always;
proxy_pass http://127.0.0.1:3000;
}
یک نکتهٔ مهم Nginx: دستورهای add_header از بلوکهای بالاتر به ارث نمیرسند اگر در بلوک پایینتر حتی یک add_header دیگر داشته باشید. پس اگر هدرهای امنیتی را در بلوک server تعریف کردهاید، در locationهایی که add_header جدید دارند باید آنها را تکرار کنید. ساختار بلوکها در آموزش پیکربندی Nginx توضیح داده شده است. اگر برنامهٔ بکاند خودش هدر Cache-Control میفرستد، معمولاً بهتر است آن را در کد برنامه تنظیم کنید تا Nginx.
ETag و Last-Modified: اعتبارسنجی سبک
وقتی مدت تازگی یک پاسخ تمام میشود، کش لزوماً آن را دور نمیاندازد. اگر سرور همراه پاسخ اول هدر ETag یا Last-Modified فرستاده باشد، مرورگر یا CDN در درخواست بعدی میپرسد «آیا این نسخه هنوز معتبر است؟». اگر محتوا تغییر نکرده باشد، سرور فقط یک پاسخ کوتاه 304 بدون بدنه برمیگرداند و کش همان نسخهٔ قبلی را استفاده میکند. این کار پهنای باند را بهشدت کم میکند، مخصوصاً برای HTML که با no-cache تنظیم شده است.
Nginx برای فایلهای استاتیک این هدرها را بهطور خودکار میفرستد. برای پاسخهای برنامه، بسیاری از فریمورکها امکان تولید ETag را دارند. اگر چند سرور پشت یک Load Balancer دارید، مطمئن شوید ETag یک فایل روی همهٔ سرورها یکسان است؛ وگرنه اعتبارسنجی همیشه شکست میخورد و کل فایل دوباره ارسال میشود.
قانونهای کش در پنل CDN
بیشتر CDNها بهطور پیشفرض فقط فایلهای استاتیک رایج را بر اساس پسوند کش میکنند و HTML را کش نمیکنند. در پنل معمولاً میتوانید:
- از هدر مبدأ پیروی کنید: CDN دقیقاً به Cache-Control سرور شما عمل میکند. اگر هدرها را درست تنظیم کردهاید، بهترین گزینه است.
- مدت کش لبه را بازنویسی کنید: برای یک مسیر یا نوع فایل، مدت مشخصی تعیین کنید بدون توجه به هدر سرور.
- مسیرهایی را از کش مستثنا کنید: مثلاً
/admin،/account،/cartو/api. - کش را بر اساس کوکی دور بزنید: اگر کاربر کوکی ورود دارد، پاسخ از کش داده نشود.
ترتیب قانونها مهم است؛ معمولاً قانونهای خاصتر باید پیش از قانونهای کلی بیایند. هر بار قانون جدیدی برای کش HTML اضافه میکنید، با یک حساب کاربری آزمایشی و یک مرورگر بدون ورود، هر دو حالت را تست کنید.
بررسی اینکه کش کار میکند
بیشتر CDNها یک هدر وضعیت کش در پاسخ اضافه میکنند که مقدارش HIT یا MISS یا مشابه آن است. با curl آن را ببینید:
curl -sI https://example.com/assets/app.3f9a2c.js | grep -iE "cache|age"
درخواست اول معمولاً MISS است چون فایل هنوز در لبه نیست؛ درخواستهای بعدی باید HIT شوند. هدر Age هم نشان میدهد پاسخ چند ثانیه است در کش مانده. اگر همیشه MISS میگیرید، دلایل رایج اینهاست: سرور no-store یا private میفرستد، پاسخ کوکی Set-Cookie دارد که بسیاری از CDNها با دیدن آن کش نمیکنند، یا رشتهٔ کوئری در هر درخواست تغییر میکند و CDN هر نسخه را جداگانه میبیند.
$ curl -sI https://example.com/assets/app.3f9a2c.js | grep -iE 'cache|age'cache-control: public, max-age=31536000, immutablex-cache-status: MISS$ curl -sI https://example.com/assets/app.3f9a2c.js | grep -iE 'cache|age'cache-control: public, max-age=31536000, immutablex-cache-status: HITage: 4$
بعد از تغییر محتوا: پاک کردن کش
وقتی محتوایی را که با مدت طولانی کش شده تغییر میدهید، کاربران تا پایان مدت نسخهٔ قدیمی را میبینند. دو راه دارید: نام فایل را نسخهدار کنید تا اصلاً به پاک کردن نیاز نباشد، یا از قابلیت پاک کردن کش در پنل CDN برای آدرسهای مشخص استفاده کنید. پاک کردن کل کش سایت فقط در موارد ضروری مناسب است، چون تا مدتی همهٔ درخواستها به سرور اصلی میروند و بار آن ناگهان بالا میرود؛ وضعیتی که اگر سرور ضعیف باشد میتواند به خطاهای 5xx در CDN منجر شود.
با یک راهبرد کش درست، بیشتر درخواستها در لبهٔ CDN پاسخ داده میشوند و سرور اصلی فقط کار واقعی را انجام میدهد.
سؤالات متداول
تفاوت no-cache و no-store چیست؟
no-cache اجازهٔ ذخیره میدهد اما پیش از هر استفاده باید اعتبار با سرور بررسی شود. no-store اصلاً اجازهٔ ذخیره نمیدهد. برای اطلاعات حساس و صفحههای شخصی، no-store درست است.
آیا کش کردن HTML در CDN خطرناک است؟
برای صفحههای عمومی که برای همه یکساناند خیر و سرعت را بسیار بهتر میکند. خطر فقط وقتی است که صفحههای شخصی یا پس از ورود کش شوند؛ این مسیرها را حتماً مستثنا کنید و با کاربر واردشده تست کنید.
چرا CDN با وجود هدر درست، فایل را کش نمیکند؟
رایجترین علتها هدر Set-Cookie در پاسخ، قانون پنل CDN که هدر را بازنویسی میکند، یا رشتهٔ کوئری متغیر است. هدرهای کامل پاسخ را با curl -I بررسی کنید.
s-maxage چه کاربردی دارد؟
به CDN و کشهای مشترک مدت جداگانهای میدهد. مثلاً HTML را در CDN چند دقیقه کش کنید اما در مرورگر هر بار بررسی شود؛ اینطور با پاک کردن کش CDN، همهٔ کاربران سریع نسخهٔ جدید را میبینند.
از ۱٬۲۰۰ تومان در ساعت · پرداخت ریالی



