وقتی راجع به کش کردن با یه بکاند دولوپر صحبت میکنید عمدتا فکرشون میره سمت ذخیره کردن دیتاهایی که زیاد تغییر نمیکنن توی RAM و استفاده از ابزارهایی مثل Redis.
ولی چرا به این فکر نمیکنیم که اگه API هایی که توسعه میدیم قراره یکی از کلاینتاش مرورگر کاربرامون باشه بیایم و از حافظه Cache مرورگر استفاده کنیم؟
مقدار این هدر مشخص میکنه که مرورگر ما با اطلاعاتی که دریافت میکنه به لحاظ کش کردن چطوری رفتار بکنه و مهم نیست که این اطلاعات از نوع تصویر، ویدیو، JSON، HTML یا .... باشه. همه رو میشه کش کرد.
البته به لحاظ فنی فقط مرورگر نیست و این هدر توی لایه Proxy Server هم میتونه کش رو انجام بده.
توی عکس زیر یه وبسرور Node.jsی داریم که قراره یه JSON برگردونه و همچنین هدر Cache-Control با مقدار private, max-age=60 هم داره که یعنی این صفحه رو روی مرورگر شخص و نه سرور پراکسی تا ۶۰ ثانیه کشش کن!
توی درخواست اول همونطور که توی تصویر زیر مشخصه ریکوئست به سرور اصلی (origin server) اومده و لاگ request received هم چاپ شده.
اما توی درخواست دوم ریکوئستی به سرور ما نیومده و ریسپانس کاربر از دیسک واکشی شده!
یه نکتهای که باید در نظر داشته باشید اینه که مرورگر موقع رفرش صفحه داخل request header ها مقدار cache-control: max-age=0 رو تنظیم میکنه که باعث میشه از کش خونده نشه ولی اگه یه تب جدید باز کنید و یا از fetch استفاده کنید برای لود کردن اون مسیر از کش استفاده میشه.
توی این مثال ما چی به دست آوردیم؟ ذخیره کردن قدرت پردازشی سرور با نیومدن ریکوئست بهش، ذخیره کردن پهنای باند.
اما لایو بودن دیتامون رو از دست دادیم.
مرورگر به صورت پیشفرض تلاش میکنه چیزهایی که دریافت میکنه رو کش کنه. یه سری هدر ها وجود دارن برای بررسی اینکه محتوا لایو هست یا نه تا اگه اطلاعات لایو بود از همون کش استفاده بکنه بجای اینکه کل محتوا رو دوباره ارسال بکنیم برای مرورگر. مثل چی؟ ETag, Last-Modified
وقتی از این هدر ها استفاده میکنیم لایو بودن دیتامون حفظ و پهنای باندمون ذخیره میشه.
مخفف Entity Tag هست و مقدار اون رو هر چیز رشتهای میتونیم تنظیم کنیم ولی باید در نظر داشته باشید که قراره بعدا مقدار این هدر با سرور ما چک بشه پس چیز بیخود نباید تنظیمش کنیم.
اینجا با رفتن به آدرس http://localhost:3000 فایل index.html برای کاربر ارسال میشه و بعد از اون طبق تصویری داخل فایل index.html داریم یه درخواست میره به مسیر wallpaper.jpg و میخواد که یه تصویر 5.1 مگابایتی رو دانلود بکنه که حجم قابل توجهی هست.
درخواست اول ?
اگه بخش timing ریکوئست wallpaper.jpg رو ببینیم واضحه که ۵۰ میلی ثانیه زمان برده تا محتوا دانلود بشه. (Content Download)
اما با رفرش کردن صفحه و درخواست دوم شرایط متفاوت میشه و چون توی دیسک داریم اون تصویر رو دیگه نیازی به Download کردن نیست ?
و همونطور که توی اسکرین شات بالا مشخصه مرورگر برای بررسی ETag یه هدر ست میکنه به اسم if-none-match و مقدار اون برابر با ETag ارسال شده ما خواهد بود.
توی استفاده از ETag ما اومدیم و فایل رو خوندیم کامل و هشش رو حساب کردیم که این فرآیند هرچی حجم فایل ما بیشتر باشه باعث میشه قدرت پردازشی بیشتری رو درگیر بکنه اونم با هر بار لود شدن تصویر!
توی file system زمان آخرین تغییر انجام شده روی فایل مشخص هست چرا نیایم و به مرورگر زمان آخرین تغییر رو بدیم و اونم سری بعدی با استفاده از این مورد بهمون جواب نده؟!
و اما بریم برای دیدن نتایج تست توی ریکوئست اول (بدون کش) ?
و ریکوئست دوم (با کش) ?
تکبیر!
و اگه به هدر ها هم نگاه کنیم میبینیم که مرورگر هدر if-modified-since رو تنظیم کرده و مقدارش رو گذاشته اون چیزی که ما به عنوان last-modified بهش داده بودیم.
یه سری نکته هست که توی بخش های بالا نتونستم اضافشون کنم به بحث و در نتیجه اینجا مینویسم (این بخش الان حکم پوشه utils توی تعیین folder structure رو داره که هرکی نمیدونه چیز جدیدی که داره به سیستم اضافه میکنه رو توی کدوم پوشه باید بذاره میذاره داخل utils ?)
همونطور که توی عنوان نوشتم این یه مقدمهای بر HTTP Caching بود و هدفم بیشتر آشنا کردنتون با این موضوع بود تا این رو هم به عنوان یه لایه کش اگه براتون فایده داره اضافش کنید و میتونید چیزایی بیشتری رو توی لینک هایی که پایین براتون میذارم مطالعه بکنید و یاد بگیرید.
شاید براتون سوال باشه که چرا کد های بالا رو با اکسپرس ننوشتم که آسون تر باشه کارم توی routing؟ جواب اینه که اکسپرس خودش ETag و Last-Modified رو ست میکنه (البته که قابل دیزیبل کردن هست) ولی از اونجایی که هدف آموزشی هست اینکه هیچی توسط فریمورک بهمون داده نشه و خودمون دقیقا بنویسیم چی میخوایم و چطوری کار بکن باعث میشه بهتر متوجه مغز مطلب بشیم.
به دلایل نا مشخص برای تصویر وقتی از last-modified استفاده میکنید دیگه اون هدر if-modified-since رو ارسال نمیکنه و حتما باید هدر cache-control: max-age=0, must-revalidate رو ست کنید!
دلیل اینکه ما کم کردن میزان استفاده از پهنای باند مهمه بحث مالیش نیست چون توی ایران حداقل پهنای باند قیمت بالایی نداره، ولی اگه تعداد ریکوئست های همزمان زیادی به سرورمون بیاد و برای یه محتوای حجیم این ریکوئستا زده شده باشه از اونجایی که پهنای باند محدوده سرعت برای کلاینتامون کم میشه.
Everything you need to know about HTTP Caching
RFC 2616 (13- Caching in HTTP)
امیدوارم علاقه مندتون کرده باشم برای بیشتر خوندن راجع به HTTP Caching
محمد محمدعلیان | 16 اردیبهشت 1401