سایت شما سریعتر از آن چیزی است که فکر میکنید — فقط مرورگر یادش رفته
یک کاربر از دفتر کار به سایت شما سر میزند، صفحه را میبیند و میرود. پنج دقیقه بعد دوباره برمیگردد. مرورگر او درخواست میفرستد، سرور شما همان فایلها را دوباره میفرستد، همان تصاویر، همان CSS، همان جاوااسکریپت. همهچیز تکراری است. کاربر هیچ تغییری نمیبیند، اما سرور شما دارد بیهوده پهنای باند مصرف میکند و کاربر هم منتظر میماند.
این دقیقاً همان جایی است که کش مرورگر وارد میشود. نه برای صرفهجویی در هزینهها، بلکه برای اینکه صفحه دوم، سوم و دهم برای کاربر تقریباً آنی باشد.
مسئله این است که بیشتر مدیران سایت هدرهای کش را اشتباه تنظیم میکنند. یا اصلاً تنظیم نمیکنند. نتیجه؟ یک سایت که روی بار اول ۲.۸ ثانیه لود میشود و روی بار دوم هم ۲.۸ ثانیه. هیچ پیشرفتی نمیکنید.
در این مقاله میگوییم دقیقاً چه هدرهایی باید بفرستید، چه مقداری برای هر کدام بگذارید، و کجا اکثر مردم اشتباه میکنند.
Cache-Control: تنها هدری که واقعاً به آن نیاز دارید
هدر Cache-Control در HTTP/1.1 معرفی شد و عملاً جایگزین هدرهای قدیمیتر مثل Expires و Pragma شد. اگر فقط یک هدر را درست کنید، همین باشد.
سادهترین شکل آن این است:
Cache-Control: public, max-age=86400
این یعنی: این فایل را میتوانید برای ۸۶۴۰۰ ثانیه (یک روز) در کش نگه دارید. public یعنی هر کسی میتواند کش کند — مرورگر کاربر، پروکسی، CDN. برای فایلهای استاتیک مثل تصاویر، CSS و JS این مقدار درست است.
فرق max-age و s-maxage — جایی که همه چیز خراب میشود
اینجا جایی است که اکثر راهنماها به آن نمیرسند. max-age به مرورگر میگوید چقدر کش کند. s-maxage به سرورهای میانی (پروکسی و CDN) میگوید چقدر کش کنند. این دو میتوانند متفاوت باشند.
مثال واقعی: شما یک صفحه HTML دارید که هر ساعت آپدیت میشود. مرورگر کاربر میتواند آن را ۳۶۰۰ ثانیه کش کند، اما CDN شما نباید بیشتر از ۶۰۰ ثانیه نگه دارد چون ترافیک سایت شما از چند سرور میگذرد و باید سریعتر تازه شود.
Cache-Control: public, max-age=3600, s-maxage=600
اینجا اشتباه میکنند: خیلیها فکر میکنند s-maxage یک گزینه پیشرفته است که لازم نیست. بعد یک CDN جلوی سایت میگذارند و میبینند تغییرات اعمال نمیشود. کاربران نسخه قدیمی صفحه را میبینند و شما فکر میکنید CDN خراب است. نه، فقط s-maxage را تنظیم نکردهاید.
نکته دیگر: اگر s-maxage را تعیین کنید، max-age را هم حتماً بگذارید. بعضی مرورگرها وقتی s-maxage میبینند، max-age را نادیده میگیرند و از مقدار پیشفرض استفاده میکنند. نتیجه؟ کش خیلی کوتاهتر از چیزی که میخواستید.
immutable: یک کلمه که درخواستهای اضافی را حذف میکند
وقتی مرورگر فایلی را کش کرده و max-age تمام نشده، هیچ درخواستی به سرور نمیفرستد. اما وقتی max-age تمام شد، چه اتفاقی میافتد؟
مرورگر یک درخواست شرطی میفرستد: «این فایل را دارم، عوض شده؟» اگر سرور بگوید «نه»، مرورگر از کش استفاده میکند. این یک رفتوبرگشت کامل است — معمولاً ۵۰ تا ۲۰۰ میلیثانیه برای هر فایل.
برای فایلهایی که نام نسخهدار دارند (مثل style.abc123.css) این رفتوبرگشت کاملاً بیهوده است. چون اگر فایل عوض شود، نامش عوض میشود و مرورگر بههرحال درخواست جدید میفرستد. پس چرا اصلاً چک کند؟
Cache-Control: public, max-age=31536000, immutable
یک سال کش، و به مرورگر بگویید «حتی چک هم نکن». این بهترین حالت برای فایلهای استاتیک با نام نسخهدار است.
اما اینجا اشتباه میکنند: immutable را روی فایلهایی میگذارند که نام نسخهدار ندارند. مثلاً style.css را با immutable کش میکنند و بعد تغییر میدهند. کاربران تا یک سال نسخه قدیمی را میبینند. immutable فقط برای فایلهایی است که نامشان شامل هش یا نسخه است. اگر این کار را نمیکنید، از immutable استفاده نکنید.
ETag: چککننده هوشمند تغییرات
ETag یک شناسه یکتا برای محتوای یک فایل است. وقتی مرورگر درخواست شرطی میفرستد، هدر If-None-Match را با مقدار ETag قبلی میفرستد. سرور مقایسه میکند و اگر فرقی نکرد، با کد 304 Not Modified پاسخ میدهد — بدون بدنه، بدون پهنای باند.
در Nginx بهصورت پیشفرض فعال است. در Apache هم معمولاً فعال است. اما اگر سایت شما روی یک سرور اشتراکی است و هاست شما آن را غیرفعال کرده، باید چک کنید.
برای فعال کردن در Apache:
FileETag MTime Size
این یعنی ETag بر اساس زمان تغییر و اندازه فایل ساخته شود. ساده و مؤثر.
در Nginx معمولاً نیازی به تنظیم نیست، اما اگر میخواهید مطمئن شوید:
etag on;
یک نکته مهم: اگر چند سرور دارید (مثلاً لود بالانسر با دو سرور)، ETag پیشفرض Apache شامل inode فایل هم میشود. این مقدار بین سرورها متفاوت است و باعث میشود مرورگر هر بار فایل را دوباره دانلود کند. راه حل: FileETag MTime Size را بگذارید و inode را حذف کنید.
نام نسخهدار: تنها راه درست برای فایلهای استاتیک
اگر فایل شما style.css است و آن را تغییر میدهید، مرورگرهایی که کش کردهاند نسخه قدیمی را میگیرند. مگر اینکه max-age را خیلی کوتاه بگذارید — که یعنی کش تقریباً بیفایده است.
راه حل استاندارد: نام فایل را عوض کنید. style.abc123.css یا style.v2.css. هر بار که محتوا تغییر میکند، نام عوض میشود. مرورگر فایل را بهعنوان یک منبع جدید میبیند و دانلود میکند. فایل قدیمی در کش میماند تا expire شود، اما کسی از آن استفاده نمیکند.
ابزارهای مدرن مثل Webpack و Vite این کار را خودکار انجام میدهند. اگر از WordPress استفاده میکنید، افزونههایی مثل WP Rocket این کار را میکنند. اگر دستی کار میکنید، فقط یک قانون ساده: هر بار فایل را تغییر دادید، نامش را هم عوض کنید.
اینجا اشتباه میکنند: نام فایل را عوض میکنند اما لینکهای داخل HTML را بهروز نمیکنند. یا بدتر، از CDN استفاده میکنند که کش قدیمی را سرو میکند. همیشه بعد از تغییر نام فایل، صفحه HTML را هم آپدیت کنید و کش CDN را پاک کنید.
مقادیر پیشنهادی برای هر نوع فایل
| نوع فایل | Cache-Control | توضیح |
|---|---|---|
| HTML | no-cache یا max-age=0 | همیشه چک شود، اما اگر تغییری نکرده 304 برگردد |
| CSS/JS با نام نسخهدار | public, max-age=31536000, immutable | یک سال، بدون چک |
| CSS/JS بدون نام نسخهدار | public, max-age=3600 | یک ساعت، بعد چک شود |
| تصاویر | public, max-age=86400 | یک روز، معمولاً کافی است |
| فونتها | public, max-age=31536000, immutable | فونتها بهندرت تغییر میکنند |
توجه کنید: no-cache به معنی «کش نکن» نیست. یعنی «قبل از استفاده، چک کن». این تفاوت مهمی است. اگر میخواهید واقعاً کش نشود، باید no-store بگذارید — که فقط برای دادههای حساس مثل اطلاعات بانکی توصیه میشود.
چطور هدرها را روی هاست خود تنظیم کنید
روی Apache، در فایل .htaccess:
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|jpg|jpeg|png|gif|svg|woff2)$">
Header set Cache-Control "public, max-age=86400"
</FilesMatch>
</IfModule>
روی Nginx، در بلاک location:
location ~* \.(css|js|jpg|jpeg|png|gif|svg|woff2)$ {
expires 1d;
add_header Cache-Control "public, max-age=86400";
}
اگر روی هاست لینوکس سرورنت هستید، میتوانید از پنل مدیریت فایل استفاده کنید و .htaccess را مستقیم ویرایش کنید. اگر دسترسی SSH دارید، حتی سادهتر است.
بعد از تنظیم، حتماً با ابزارهایی مثل ابزارهای رایگان وبمستر چک کنید که هدرها درست ارسال میشوند. یک اشتباه رایج: هدر را تنظیم میکنید اما ماژول mod_headers در Apache فعال نیست. نتیجه؟ هیچ اتفاقی نمیافتد و شما فکر میکنید تنظیمات درست است.
یک سناریوی واقعی: چه اتفاقی میافتد وقتی همهچیز درست باشد
فرض کنید یک صفحه با ۵۰ فایل استاتیک دارید. بدون کش، هر بار بازدید ۵۰ درخواست به سرور میرود. با کش درست، بار اول ۵۰ درخواست، بار دوم ۵۰ درخواست شرطی (با 304)، بار سوم ۰ درخواست.
عدد واقعی: با کش درست، زمان بارگذاری صفحه دوم معمولاً ۵۰ تا ۷۰ درصد کمتر از بار اول است. اگر بار اول ۳ ثانیه باشد، بار دوم باید زیر ۱ ثانیه باشد. اگر این اتفاق نمیافتد، یا کش تنظیم نشده یا چیزی اشتباه است.
برای عیبیابی، از تب Network در DevTools مرورگر استفاده کنید. ستون Size را ببینید. اگر 304 Not Modified میبینید، کش کار میکند. اگر 200 OK با حجم کامل میبینید، کش کار نمیکند.
اگر سایت شما هنوز کند است و کش هم درست است، مشکل جای دیگری است. راهنمای کامل عیبیابی سایت کند را بخوانید — از DNS تا دیتابیس.
پرسشهای پرتکرار
فرق کش مرورگر و کش سرور چیست؟
کش مرورگر روی دستگاه کاربر ذخیره میشود و فقط برای همان کاربر کار میکند. کش سرور (مثل Varnish یا Redis) روی سرور است و برای همه کاربران کار میکند. این دو مکمل هم هستند، نه جایگزین هم.
کش مرورگر پهنای باند سرور را کم میکند و سرعت را برای کاربر تکراری بالا میبرد. کش سرور بار دیتابیس را کم میکند و سرعت را برای همه بالا میبرد. اگر فقط یکی را میتوانید تنظیم کنید، کش مرورگر را انتخاب کنید — سادهتر و مؤثرتر است.
چرا با وجود تنظیم Cache-Control، فایلها هنوز دانلود میشوند؟
سه دلیل رایج دارد. اول: هدر را روی فایل اشتباهی تنظیم کردهاید — مثلاً روی HTML به جای CSS. دوم: مرورگر در حالت ناشناس (Incognito) است که کش را غیرفعال میکند. سوم: هدر دیگری مثل Pragma: no-cache یا Cache-Control: no-store از سمت دیگری ارسال میشود و تنظیم شما را override میکند.
با DevTools مرورگر، تب Network، هدرهای پاسخ را بررسی کنید. ببینید دقیقاً چه مقدار Cache-Control ارسال میشود. اگر مقدار درست نیست، مشکل از تنظیمات شماست، نه مرورگر.
آیا ETag برای همه فایلها لازم است؟
برای فایلهای استاتیک که با نام نسخهدار و immutable کش میشوند، ETag بیفایده است — چون مرورگر اصلاً چک نمیکند. اما برای فایلهای HTML که no-cache دارند، ETag ضروری است تا مرورگر بتواند تشخیص دهد محتوا عوض شده یا نه.
اگر ETag را غیرفعال کنید، مرورگرها معمولاً از تاریخ آخرین تغییر (Last-Modified) استفاده میکنند. این هم کار میکند، اما دقت کمتری دارد — مخصوصاً اگر فایل در همان ثانیه تغییر کند.
کش مرورگر چقدر میتواند سرعت سایت را بهبود دهد؟
برای کاربرانی که قبلاً سایت را باز کردهاند، معمولاً ۵۰ تا ۷۰ درصد کاهش در زمان بارگذاری. برای کاربر جدید، هیچ تأثیری ندارد. به همین دلیل کش مرورگر را با کش سرور ترکیب میکنند — یکی برای کاربر جدید، یکی برای کاربر تکراری.
اگر سایت شما محتوای زیادی دارد و کاربران بارها برمیگردند، کش مرورگر بزرگترین برد سریع شماست. چند خط تنظیمات، بدون هیچ هزینه سختافزاری.
دیدگاهها ۰
هنوز دیدگاهی ثبت نشده؛ اولین نفر باشید!