أساسيات التخزين المؤقت للعميل بكلمات وأمثلة واضحة. آخر تعديل ، Etag ، انتهاء الصلاحية ، التحكم في ذاكرة التخزين المؤقت: max-age ورؤوس أخرى

يعتقد الكثير من الناس أن ملفات CSS المتصلة افتراضيًا عبر رابط أو استيراد لا يتم تخزينها مؤقتًا. لا بد لي من أن يخيب ظنك. إنه بالضبط css المخزن مؤقتًا في ملف منفصل ، وهو جيد جدًا ، أود أن أقول ممتاز. يتم التحقق من هذه المعلومات بشكل موثوق على كل من 6 وما فوق والمتصفحات الأخرى. ومن الجدير بالذكر أن العديد من المحبوبين يخزن مثل هذه الملفات بسرعة فائقة ، إذا جاز التعبير ، يحتل المركز الأول في هذه الحالة. بالمناسبة ، لهذه الآلية بالذات ، تتمتع Opera في كثير من الحالات بسرعة كبيرة مقارنة بالمتصفحات الأخرى. لكنني سأحجز على الفور أن هذا التخزين المؤقت "الفائق" في Opera يعد مزحة قاسية عند استخدام تقنية AJAX. بينما يقوم الآخرون بتعديل المجموعات الصغيرة عند استخدام AJAX ، يأخذ Opera القديم. لكن هذه أغنية لموضوع منفصل.

التخزين المؤقت لـ CSS

لكن! لا تزال هناك بعض مشاكل الحزن في هذا الاتجاه. يرجع هذا ، كقاعدة عامة ، إلى خادم Apache الذي تم تكوينه بشكل غير صحيح ، والذي ينتج عناوين غير صحيحة. وبمساعدة الرأس ، يمكنك التحكم في التخزين المؤقت للملفات. بشكل افتراضي ، بالطبع ، يتم تمكين ذاكرة التخزين المؤقت دائمًا. ولكن هناك أوقات لا تحتاج فيها إلى تخزين الملفات مؤقتًا. لهذا ، يبدأ المحترفون في الرقص مع الدف حول رؤوس HTTP. ولكن إذا كنت تقرأ هذا المقال بالكامل ، فأنت لا تزال بعيدًا جدًا عن إدارة رؤوس HTTP. أؤكد لك أنك لن تواجه مثل هذه المهمة في المستقبل القريب. ومع ذلك ، إذا كنت مهتمًا بالجوهر ، فسوف أخبرك بإيجاز كيف يحدث هذا.

  1. يرسل رأس HTTP إلى خادم WEB - يقولون ، مرحبًا ، فلفل حلو ، أعطني ملف CSS ، وإلا لدي CSS ، ولكن تم إجراء مثل هذه التغييرات مؤخرًا.
  2. ويقول له الخادم رداً على ذلك ، جميل جدًا ، لم تكن هناك تغييرات منذ تلك اللحظة ، خذ واستخدم CSS القديم بجرأة.
  3. إذا تغير CSS ، فسيقوم المتصفح بتحديث CSS بغباء في ذاكرة التخزين المؤقت الخاصة به.

حسنًا ، الآن ، إذا لم تكن متعبًا ، فهناك القليل من القمامة العلمية من نوع من التجارب.

سأخبرك على الفور أن النص السفلي لن يفهم جيدًا من قبل المبتدئين في WEB. في الأساس ، سيكون هذا مفيدًا لأولئك الذين لا يزالون يواجهون مهام تعطيل ذاكرة التخزين المؤقت وتمكينها.

أجريت جميع التجارب على أساس حقيقي مدفوع الأجر. مضيف جيد ، إذا جاز التعبير ، يسمح لك بتغيير بنية رؤوس HTTP دون الاضطرار إلى جنون العظمة من أنه سيتم اختراقه بواسطة رأس HTTP :)

أوضاع المتصفح

لذلك أي متصفح لديه 2 أوضاع:

1. الوضع الافتراضي، العنوان الذي تم إرجاعه هو:

التحكم في ذاكرة التخزين المؤقت: no-store ، no-cache ، must-revalidate ، post-check = 0 ، pre-check = 0

2. وضع تمكين التخزين المؤقت، العنوان الذي تم إرجاعه هو:

التحكم في ذاكرة التخزين المؤقت: خاص ، الحد الأقصى للعمر = 10800 ، الفحص المسبق = 10800

بعد ذلك ، أصف سلوك المتصفحات

FireFox 3.5 والإصدارات الأحدث

في الاوليقوم الوضع بتخزين ملفات JavaScript الخارجية بشكل مؤقت ولا يتحقق حتى من وجود تحديثات ، إلا إذا قمت بإجبار الصفحة على التحديث. يتم التحقق من صحة CSS من خلال طلب رأس.

If-Modified-Since: "التاريخ الحالي" GMT If-None-Match: "own hash code"

أي أنه لا يتم إعادة تحميل CSS إلا إذا تم تحديثه بالفعل.

ثانيايتوقف الوضع عن تحديث الصفحة تمامًا. أي ، حتى إذا قمنا بتغيير المحتوى المعروض على الصفحة في قاعدة البيانات ، فإنه لا يعرض هذا ، حتى إذا تم إجباره على التحديث ، لأنه يرسل طلبًا:

GET / HTTP / 1.1 Host: xxx.com If-Modified-Since: تاريخ GMT الحالي

ويحصل على الجواب:

HTTP / 1.1 304 غير معدل

Internet Explorer 8 (IE8)

في الاوليرسل وضع Internet Explorer طلبات If-Modified-Since & If-None-Match لكل من JavaScript و css ، أي أنه يقوم بتحميل JavaScript و CSS فقط إذا تم تحديثهما بالفعل. وينطبق الشيء نفسه إذا تم إجبار الصفحة على التحديث.

ثانيايرسل وضع Internet Explorer أيضًا طلبات If-Modified-Since & If-None-Match لكل من JavaScript و css. لكن في الوقت نفسه ، لا يحاول حتى تحميل / تحديث الصفحة نفسها ، أي أنه لا يرسل حتى طلبًا ، أي أنه سيتم تحديث js / css ، لكن لن يتم تحديث القالب ومحتوى الصفحة. حتى التحديث الإجباري للصفحة لا يساعد في تحديث المحتوى.

أوبرا 10 وما فوق

في الاولوضع Opera ، في الوضع الأول ، يعتمد تحديث js & CSS على قيمة خيار التحقق من الصور في الإعدادات. إذا تم تعيين الخيار على دائمًا ، فإن الأوبرا ترسل طلبات مع If-Modified-Since & If-None-Match للتحقق من تحديثات js & css. إذا تم تعيين قيمة ، على سبيل المثال ، 5 ساعات ، فحينئذٍ ، سيتم فحصها مرة واحدة كل 5 ساعات ، أو عن طريق التحديث الإجباري للصفحة.

ثانياالوضع ، لا يتحقق Opera من تحديثات js & CSS (لا يقدم طلبات GET) ، كما أنه لا يقدم طلب GET للصفحة نفسها ، أي أننا لن نرى تحديثات js & css أو تحديثات المحتوى ، كما في أشياء أخرى وفي متصفحات أخرى. ولكن مع التحديث الإجباري ، فإن Opera أفضل. بخلاف IE & FF ، يطلب Opera صراحة محتوى الصفحة بدون If-Modified-Since & If-None-Match. تأتي طلبات تحديث Js و CSS للتحديث الإجباري مع If-Modified-Since & If-None-Match.

الاستنتاجات

  1. التخزين المؤقت ، إذا كنت لا تفهم بالضبط كيف يعمل في متصفحات مختلفة وما هي العواقب ، فهو أمر خطير إلى حد ما.
  2. لا يمكن تمكين التخزين المؤقت إلا إذا نادراً ما يتم تحديث الصفحة (أي إذا لم يكن الموقع يحتوي على صفحات يتم تحديثها في الوقت الفعلي) وحتى في هذه الحالة ، من الضروري تعيين حد لفترة تقييد التخزين المؤقت (على سبيل المثال ، بضع ساعات أو يوم)
  3. يتصرف FireFox ، في رأيي ، أكثر ذكاءً قليلاً من IE ، لأنه حتى مع تعطيل التخزين المؤقت ، فإنه لا يبحث باستمرار عن تحديثات JavaScript ، وهو ما يبدو منطقيًا ، لأن JavaScript نادرًا ما يتم تحديثه.
  4. يتيح لك Opera التحكم بمرونة في تحديث الصور و JavaScript و CSS باستخدام إعداد التحقق من الصور ، وهو ميزة إضافية. يتصرف Opera أيضًا بشكل أفضل من IE & FF مع تمكين التخزين المؤقت والتحديث الإجباري ، لأنه ، اسمحوا لي أن أذكرك ، يقوم Opera بتحديث محتوى الصفحة بالكامل في هذه الحالة ، وسوف يتركك IE & FF في جهل سعيد.

حظا سعيدا ومواقع مربحة.

يوفر التخزين المؤقت الذي تم تكوينه بشكل صحيح مكاسب هائلة في الأداء ، ويوفر النطاق الترددي ، ويقلل من تكاليف الخادم ، ولكن العديد من المواقع لا تنفذ التخزين المؤقت جيدًا ، مما يؤدي إلى حدوث حالة سباق تؤدي إلى عدم مزامنة الموارد المترابطة.

تقع الغالبية العظمى من أفضل ممارسات التخزين المؤقت في أحد نمطين:

النمط رقم 1: المحتوى غير القابل للتغيير والعمر الأقصى الطويل لذاكرة التخزين المؤقت

التحكم في ذاكرة التخزين المؤقت: الحد الأقصى للعمر = 31536000
  • لا يتغير المحتوى الموجود على عنوان URL ، لذلك ...
  • يمكن للمتصفح أو CDN تخزين مورد مؤقتًا لمدة عام دون أي مشاكل
  • يمكن استخدام المحتوى المخزن مؤقتًا الأصغر من الحد الأقصى للعمر المحدد دون استشارة الخادم

صفحة : مرحبًا ، أحتاج إلى "/script-v1.js" و "/styles-v1.css" و "/cats-v1.jpg" 10:24

مخبأ : انا فارغ ماذا عن خادمك؟ 10:24

الخادم : حسنًا ، ها هم. بالمناسبة ، نقدًا ، يجب استخدامها في غضون عام ، لا أكثر. 10:25

مخبأ : شكرا! 10:25

صفحة : الصيحة! 10:25

في اليوم التالي

صفحة : مرحبًا ، أحتاج "/ script- الإصدار 2.js "،" / styles- الإصدار 2.css "و" /cats-v1.jpg "08:14

مخبأ : هناك صورة مع القطط ، والباقي ليس كذلك. الخادم؟ 08:14

الخادم : سهل - إليك CSS & JS الجديدان. مرة أخرى ، كاش: مدة صلاحيتها لا تزيد عن عام. 08:15

مخبأ : ممتاز! 08:15

صفحة : شكرا! 08:15

مخبأ : حسنًا ، لم أستخدم "/script-v1.js" & "/styles-v1.css" لفترة كافية. حان الوقت لحذفها. 12:32

باستخدام هذا النمط ، لا يمكنك تغيير محتوى عنوان URL محدد ، يمكنك تغيير عنوان URL نفسه:

يحتوي كل عنوان URL على شيء يتغير مع المحتوى. يمكن أن يكون هذا رقم إصدار أو تاريخًا معدلًا أو تجزئة للمحتوى (هذا هو الخيار الذي اخترته لمدونتي).

تحتوي معظم الأطر من جانب الخادم على أدوات للقيام بهذا النوع من الأشياء بسهولة (في Django أستخدم Manifest Static Files Storage) ؛ هناك أيضًا مكتبات صغيرة جدًا في Node.js تقوم بنفس الشيء ، مثل gulp-rev.

ومع ذلك ، فإن هذا النمط غير مناسب لأشياء مثل المقالات ومشاركات المدونات. لا يمكن تغيير إصدارات عناوين URL الخاصة بهم ويمكن تغيير محتواها. على محمل الجد ، لدي الكثير من الأخطاء النحوية وعلامات الترقيم وأريد أن أكون قادرًا على تحديث المحتوى بسرعة.

النمط رقم 2: محتوى قابل للتغيير يتم إعادة التحقق منه دائمًا على الخادم

التحكم في ذاكرة التخزين المؤقت: عدم وجود ذاكرة التخزين المؤقت
  • سيتغير محتوى عنوان URL ، لذا ...
  • لا يمكن استخدام أي نسخة محلية مخبأة بدون تحديد خادم.

صفحة : مرحبًا ، أحتاج إلى محتويات "/ about /" و "/sw.js" 11:32

مخبأ : لا يمكن أن تساعد في ذلك. الخادم؟ 11:32

الخادم : هناك مثل هذا. كاش ، احتفظ بها معك ، لكن اسألني قبل استخدامها. 11:33

مخبأ : نعم سيدي! 11:33

صفحة : شكرا! 11:33

في اليوم التالي

صفحة : مرحبًا ، أحتاج إلى محتويات "/ about /" و "/sw.js" مرة أخرى 09:46

مخبأ : انتظر دقيقة. الخادم ، هل نسخي بخير؟ نسخة من "/ about /" من يوم الاثنين ، و "/sw.js" من الأمس. 09:46

الخادم : لم يتغير "/sw.js" ... 09:47

مخبأ : رائع. الصفحة ، اضغط باستمرار على "/sw.js". 09:47

الخادم : ... لكن "/ about /" لدي نسخة جديدة. كاش ، امسكها ، لكن مثل المرة السابقة ، تذكر أن تسألني أولاً. 09:47

مخبأ : فهمت! 09:47

صفحة : بخير! 09:47

ملاحظة: لا تعني no-cache "عدم التخزين المؤقت" ، بل تعني "التحقق" (أو إعادة التحقق) من المورد المخزن مؤقتًا من الخادم. أمر no-store المتصفح بعدم التخزين المؤقت على الإطلاق. أيضًا ، لا تعني must-revalidate إعادة التحقق الإلزامية ، ولكن حقيقة أن المورد المخزن مؤقتًا يُستخدم فقط إذا كان أصغر من الحد الأقصى للعمر المحدد ، وإلا فإنه يتم إعادة التحقق منه. هذه هي الطريقة التي يبدأ بها تخزين الكلمات الرئيسية في ذاكرة التخزين المؤقت.

في هذا النمط ، يمكنك إضافة ETag (معرف إصدار من اختيارك) أو رأس Last-Modified إلى الاستجابة. في الطلب التالي للمحتوى من العميل ، يقوم بإخراج If-None-Match أو If-Modified-Since ، على التوالي ، مما يسمح للخادم بأن يقول "استخدم ما لديك ، ذاكرة التخزين المؤقت الخاصة بك محدثة" ، وهو إعادة HTTP 304.

إذا تعذر إرسال ETag / Last-Modified ، يرسل الخادم المحتوى بالكامل دائمًا.

يتطلب هذا النمط دائمًا طلبات الشبكة ، لذا فهو ليس بجودة النمط الأول الذي يمكنه الاستغناء عن طلبات الشبكة.

ليس من غير المألوف عدم توفر البنية التحتية للنمط الأول ، ولكن بنفس الطريقة يمكن أن تنشأ مشاكل مع طلبات الشبكة في النمط 2. ونتيجة لذلك ، يتم استخدام خيار وسيط: محتوى قصير وقابل للتغيير. هذه تسوية سيئة.

عادةً ما يكون استخدام max-age مع محتوى قابل للتغيير اختيارًا خاطئًا.

ولسوء الحظ ، فهي منتشرة على نطاق واسع ، ويمكن أخذ صفحات Github كمثال.

يتصور:

  • / مقالة - سلعة /
  • /styles.css
  • /script.js

مع رأس من جانب الخادم:

التحكم في ذاكرة التخزين المؤقت: يجب إعادة التحقق ، الحد الأقصى للعمر = 600

  • يتغير محتوى URL
  • إذا كان المتصفح يحتوي على نسخة مخبأة جديدة لمدة 10 دقائق ، فسيتم استخدامه دون استشارة الخادم
  • إذا لم يكن هناك ذاكرة تخزين مؤقت من هذا القبيل ، فسيتم استخدام طلب شبكة ، ربما مع If-Modified-Since أو If-None-Match

صفحة : مرحبًا ، أحتاج إلى "/ article /" و "/script.js" و "/styles.css" 10:21

مخبأ : ليس لدي شيء مثلك ، الخادم؟ 10:21

الخادم : لا مشكلة ، ها هم. لكن تذكر ، كاش: يمكن استخدامها في غضون الدقائق العشر القادمة. 10:22

مخبأ : هنالك! 10:22

صفحة : شكرا! 10:22

صفحة : مرحبًا ، أحتاج إلى "/ article /" و "/script.js" و "/styles.css" مرة أخرى 10:28

مخبأ : عفوًا ، أنا آسف ، لكنني فقدت "/styles.css" ، لكن لدي كل شيء آخر ، خذها. الخادم ، هل يمكنك تخصيص "/styles.css" لي؟ 10:28

الخادم : سهل ، لقد تغير بالفعل منذ آخر مرة التقطته. يمكنك استخدامه بأمان لمدة 10 دقائق القادمة. 10:29

مخبأ : لا مشكلة. 10:29

صفحة : شكرا! لكن يبدو أنه حدث خطأ ما! يتم تقسيم كل شيء! ما الذي يجري؟ 10:29

من حق هذا النمط أن يعيش تحت الاختبار ، لكنه يكسر كل شيء في مشروع حقيقي ويصعب جدًا تتبعه. في المثال أعلاه ، قام الخادم بتحديث HTML و CSS و JS ، ولكن يتم عرض الصفحة مع HTML و JS القديم من ذاكرة التخزين المؤقت ، والتي تمت إضافة CSS المحدث من الخادم إليها. عدم تطابق الإصدار يفسد كل شيء.

غالبًا عند إجراء تغييرات مهمة على HTML ، نقوم بتغيير كل من CSS لتعكس البنية الجديدة بشكل صحيح ، و JavaScript لمواكبة المحتوى والأنماط. كل هذه الموارد مستقلة ، لكن رؤوس ذاكرة التخزين المؤقت لا يمكنها التعبير عن ذلك. نتيجة لذلك ، قد يكون لدى المستخدمين أحدث إصدار من مورد واحد أو اثنين وإصدار قديم من الباقي.

يتم تعيين max-age بالنسبة إلى وقت الاستجابة ، لذلك إذا تم نقل جميع الموارد كجزء من نفس العنوان ، فستنتهي صلاحيتها في نفس الوقت ، ولكن لا تزال هناك فرصة ضئيلة للإلغاء. إذا كانت لديك صفحات لا تتضمن جافا سكريبت أو تتضمن أنماطًا أخرى ، فستكون تواريخ انتهاء ذاكرة التخزين المؤقت الخاصة بها غير متزامنة. والأسوأ من ذلك ، يقوم المتصفح بسحب المحتوى باستمرار من ذاكرة التخزين المؤقت ، دون أن يعرف أن HTML و CSS و JS مترابطان ، لذلك يمكنه بسعادة إخراج أحدهما من القائمة ونسيان كل شيء آخر. بالنظر إلى كل هذه العوامل معًا ، يجب أن تفهم أن احتمالية عدم تطابق الإصدارات عالية جدًا.

بالنسبة للمستخدم ، قد تكون النتيجة تخطيط صفحة معطل أو مشاكل أخرى. من مواطن الخلل الصغيرة إلى المحتوى غير القابل للاستخدام تمامًا.

لحسن الحظ ، لدى المستخدمين مخرج طوارئ ...

تحديث الصفحة يحفظ في بعض الأحيان

إذا تم تحميل الصفحة عن طريق التحديث ، تقوم المتصفحات دائمًا بإعادة التحقق من جانب الخادم ، متجاهلة max-age. لذلك ، إذا كان لدى المستخدم شيء مكسور بسبب الحد الأقصى للعمر ، يمكن أن يؤدي تحديث الصفحة البسيط إلى إصلاح كل شيء. لكن ، بالطبع ، بعد العثور على الملاعق ، ستظل الرواسب قائمة وسيختلف الموقف تجاه موقعك إلى حد ما.

يمكن لعامل الخدمة إطالة عمر هذه الأخطاء.

على سبيل المثال ، لديك عامل خدمة مثل هذا:

إصدار Const = "2" ؛ self.addEventListener ("install"، event => (event.waitUntil (caches.open (`static - $ (version)`). ثم (cache => cache.addAll (["/styles.css"، "/ script .js "]))) ؛)) ؛ self.addEventListener ("التنشيط" ، الحدث => (// ... حذف ذاكرة التخزين المؤقت القديمة ...)) ؛ self.addEventListener ("fetch"، event => (event.respondWith (caches.match (event.request). ثم (response => response || fetch (event.request))) ؛)) ؛

عامل الخدمة هذا:

  • مخبأ النصي والأنماط
  • يستخدم ذاكرة التخزين المؤقت عند المطابقة ، وإلا فإنه يصل إلى الشبكة

إذا قمنا بتغيير CSS / JS ، فسنزيد أيضًا من رقم الإصدار ، مما يؤدي إلى إجراء تحديث. ومع ذلك ، نظرًا لأن addAll يصل إلى ذاكرة التخزين المؤقت أولاً ، فقد ينتهي بنا الأمر في حالة سباق بسبب الحد الأقصى للعمر وإصدارات CSS & JS غير المتطابقة.

بعد أن يتم تخزينها مؤقتًا ، سيكون لدينا CSS & JS غير متوافقين حتى التحديث التالي لعامل الخدمة - وهذا إذا لم نصل مرة أخرى إلى حالة سباق أثناء التحديث.

يمكنك تخطي التخزين المؤقت في عامل الخدمة:

Self.addEventListener ("install"، event => (event.waitUntil (caches.open (`static - $ (version)`). ثم (cache => cache.addAll ([new Request ("/ styles.css"، (cache: "no-cache")) ، طلب جديد ("/ script.js" ، (cache: "no-cache"))]))) ؛)) ؛

لسوء الحظ ، لا يتم دعم خيارات التخزين المؤقت في Chrome / Opera وقد تمت إضافتها للتو إلى Firefox البناء الليلي ، ولكن يمكنك القيام بذلك بنفسك:

Self.addEventListener ("install"، event => (event.waitUntil (caches.open (`static - $ (version)`). ثم (cache => Promise.all (["/styles.css"، "/ script .js "] .map (url => (// cache-bust باستخدام سلسلة استعلام عشوائية عودة جلب (` $ (url)؟ $ (Math.random ()) `). ثم (response => (// fail في 404 ، 500 وما إلى ذلك إذا (! response.ok) ألقى خطأ ("ليس على ما يرام") ؛ قم بإرجاع cache.put (url ، response) ؛)))))))) ؛)) ؛

في هذا المثال ، أقوم بمسح ذاكرة التخزين المؤقت باستخدام رقم عشوائي ، ولكن يمكنك المضي قدمًا وإضافة تجزئة للمحتوى في الإنشاء (يشبه هذا ما يفعله sw-precache). هذا نوع من تنفيذ JavaScript للنمط الأول ، ولكنه يعمل فقط مع عامل الخدمة ، وليس المتصفحات وشبكات CDN.

يعمل عمال الخدمة وذاكرة التخزين المؤقت HTTP بشكل رائع معًا ، فلا تجعلهم يقاتلون!

كما ترى ، يمكنك التغلب على أخطاء التخزين المؤقت في عامل الخدمة لديك ، ولكن من الأفضل معالجة جذر المشكلة. لا يؤدي إعداد التخزين المؤقت بشكل صحيح إلى تسهيل عمل عامل الخدمة فحسب ، بل يساعد أيضًا المتصفحات التي لا تدعم عمال الخدمة (Safari و IE / Edge) ويسمح لك أيضًا بالحصول على أقصى استفادة من CDN الخاص بك.

يمكن أن تجعل رؤوس التخزين المؤقت الصحيحة أيضًا من السهل جدًا تحديث عامل الخدمة.

إصدار Const = "23" ؛ self.addEventListener ("install"، event => (event.waitUntil (caches.open (`static - $ (version)`). ثم (cache => cache.addAll (["/"، "/ script-f93bca2c. js "،" /styles-a837cb1e.css "،" /cats-0e9a2ef4.jpg "]))) ؛)) ؛

لقد قمت هنا بتخزين الصفحة الجذر مؤقتًا باستخدام النمط رقم 2 (إعادة التحقق من جانب الخادم) وجميع الموارد الأخرى ذات النمط رقم 1 (محتوى غير قابل للتغيير). سيؤدي كل تحديث لعامل الخدمة إلى طلب إلى الصفحة الرئيسية ، وسيتم تحميل جميع الموارد الأخرى فقط إذا تم تغيير عنوان URL الخاص بها. الخبر السار هو أنه يوفر حركة المرور ويحسن الأداء ، سواء كنت تقوم بالترقية من إصدار سابق أو إصدار قديم جدًا.

هناك ميزة كبيرة على التنفيذ الأصلي هنا ، حيث يتم تنزيل الثنائي بأكمله حتى مع تغيير بسيط ، أو استدعاء مقارنات ثنائية معقدة. بهذه الطريقة يمكننا تحديث تطبيق ويب كبير بحمل صغير نسبيًا.

يعمل عمال الخدمة بشكل أفضل كتعزيز بدلاً من عكاز مؤقت ، لذا اعمل مع ذاكرة التخزين المؤقت بدلاً من محاربتها.

عند الاستخدام بعناية ، يمكن أن يكون المحتوى ذو الحد الأقصى للعمر والمحتوى القابل للتغيير جيدًا جدًا.

max-age غالبًا ما يكون الاختيار الخاطئ للمحتوى القابل للتغيير ، ولكن ليس دائمًا. على سبيل المثال ، يبلغ الحد الأقصى لعمر المقالة الأصلية ثلاث دقائق. لا تمثل ظروف العرق مشكلة نظرًا لعدم وجود تبعيات على الصفحة باستخدام نفس نمط التخزين المؤقت (تستخدم CSS و JS والصور النمط رقم 1 - محتوى غير قابل للتغيير) ، وكل شيء آخر لا يستخدم هذا النمط.

يعني هذا النمط أنني أكتب بهدوء مقالًا شائعًا ، ويمكن لـ CDN (Cloudflare) الخاص بي إزالة الحمل من الخادم ، إذا كنت ، بالطبع ، على استعداد للانتظار لمدة ثلاث دقائق حتى تصبح المقالة المحدثة متاحة للمستخدمين.

يجب استخدام هذا النمط بدون تعصب. إذا أضفت قسمًا جديدًا إلى مقال ، وربطته من مقال آخر ، فقد قمت بإنشاء تبعية تحتاج إلى حل. يمكن للمستخدم الضغط على الرابط والحصول على نسخة من المقال بدون القسم الذي يبحث عنه. إذا أردت تجنب ذلك ، يجب أن أقوم بتحديث المقالة ، وحذف النسخة المخبأة من المقالة من Cloudflare ، وانتظر ثلاث دقائق ، وبعد ذلك فقط أضف الرابط إلى مقالة أخرى. نعم ، هذا النمط يتطلب الحذر.

عند استخدامه بشكل صحيح ، يمكن أن يوفر التخزين المؤقت أداءً كبيرًا وتوفيرًا في النطاق الترددي. قم بتمرير المحتوى غير القابل للتغيير إذا كان بإمكانك تغيير عنوان URL بسهولة ، أو استخدام إعادة التحقق من جانب الخادم. امزج بين محتوى max-age والمحتوى القابل للتغيير إذا كنت جريئًا بما يكفي للتأكد من أن المحتوى الخاص بك لا يحتوي على أي تبعيات قد تخرج عن المزامنة.

من خلال تضمين CSS و Javascript خارجي ، نريد تقليل طلبات HTTP غير الضرورية إلى الحد الأدنى.

لهذا ، يتم تقديم ملفات .js و. cs برؤوس توفر تخزينًا مؤقتًا موثوقًا به.

ولكن ماذا لو تغير أي من هذه الملفات أثناء التطوير؟ جميع المستخدمين لديهم إصدار قديم في ذاكرة التخزين المؤقت - حتى تصبح ذاكرة التخزين المؤقت قديمة ، ستظهر الكثير من الشكاوى حول تكامل معطل لأجزاء الخادم والعميل.

الطريقة الصحيحة للتخزين المؤقت والإصدارات تقضي تمامًا على هذه المشكلة وتضمن مزامنة موثوقة وشفافة لإصدارات النمط / البرنامج النصي.

من السهل ETag التخزين المؤقت

أسهل طريقة لتخزين الموارد الثابتة مؤقتًا هي استخدام ETag.

يكفي تمكين إعداد الخادم المناسب (بالنسبة إلى Apache ، يتم تمكينه افتراضيًا) - وسيتم منح ETag لكل ملف في الرؤوس - وهو تجزئة تعتمد على وقت التحديث وحجم الملف و (على أنظمة الملفات المستندة إلى inode ) inode.

يقوم المستعرض بتخزين مثل هذا الملف مؤقتًا ، وبناءً على الطلبات اللاحقة ، يحدد عنوان If-None-Match من ETag للمستند المخبأ. بعد تلقي مثل هذا الرأس ، يمكن للخادم الاستجابة برمز 304 - وبعد ذلك سيتم أخذ المستند من ذاكرة التخزين المؤقت.

تبدو هكذا:

الطلب الأول إلى الخادم (ذاكرة التخزين المؤقت نظيفة) GET /misc/pack.js HTTP / 1.1 Host: site

بشكل عام ، يضيف المتصفح عادةً مجموعة من الرؤوس مثل User-Agent و Accept وما إلى ذلك. يتم قطعها للإيجاز.

استجابة الخادم يرسل الخادم ردًا على مستند برمز 200 و ETag: HTTP / 1.x 200 OK ترميز المحتوى: gzip Content-Type: text / javascript؛ charset = utf-8 Etag: "3272221997" Accept-Ranges: bytes Content-Length: 23321 التاريخ: الجمعة ، 02 مايو 2008 17:22:46 GMT Server: lighttpd طلب المستعرض التالي عند الطلب التالي يضيف المتصفح If-None-Match: (ETag المخزنة مؤقتًا): GET /misc/pack.js HTTP / 1.1 Host: site If-None-Match: "453700005" استجابة الخادم يبحث الخادم - نعم ، لم يتغير المستند. هذا يعني أنه يمكنك إصدار الرمز 304 وعدم إرسال المستند مرة أخرى. HTTP / 1.x 304 غير معدل ترميز المحتوى: gzip Etag: "453700005" نوع المحتوى: text / javascript؛ charset = utf-8 Accept-Ranges: bytes Date: Tue، 15 Apr 2008 10:17:11 GMT

بدلاً من ذلك ، إذا تم تغيير المستند ، فسيرسل الخادم 200 مع ETag جديد.

تعمل الحزمة Last-Modified + If-Modified-Since بطريقة مماثلة:

  1. يرسل الخادم تاريخ آخر تعديل في رأس Last-Modified (بدلاً من ETag)
  2. يقوم المستعرض بتخزين المستند مؤقتًا ، وفي الطلب التالي لنفس المستند يرسل تاريخ الإصدار المخزن مؤقتًا في عنوان If-Modified-Since (بدلاً من If-None-Match)
  3. يتحقق الخادم من التواريخ ، وإذا لم يتغير المستند ، فسيرسل الرمز 304 فقط ، بدون محتوى.

تعمل هذه الطرق بشكل مستقر وجيد ، ولكن يجب على المتصفح القيام بذلك عند الطلب على أي حال لكل نص أو نمط.

التخزين المؤقت الذكي. الإصدار

النهج العام للإصدار باختصار:

  1. تتم إضافة الإصدار (أو تاريخ التعديل) إلى كافة البرامج النصية. على سبيل المثال ، http: // site / my.jsسيتحول إلى http: // site / my.v1.2.js
  2. يتم تخزين جميع البرامج النصية مؤقتًا بواسطة المستعرض
  3. عندما يتم تحديث البرنامج النصي ، يتغير الإصدار إلى إصدار جديد: http: // site / my.v2.0.js
  4. تم تغيير العنوان ، لذلك سيطلب المتصفح الملف ويخزنه مؤقتًا مرة أخرى
  5. الإصدار القديم 1.2 سوف يسقط تدريجياً من ذاكرة التخزين المؤقت

الصعب التخزين المؤقت

الصعب التخزين المؤقت- نوع من مطرقة ثقيلة يقوم بمسامير الطلبات بشكل كامل إلى الخادم للوثائق المخزنة مؤقتًا.

للقيام بذلك ، ما عليك سوى إضافة Expires and Cache-Control: max-age headers.

على سبيل المثال ، للتخزين المؤقت لمدة 365 يومًا في PHP:

Header ("Expires:" .gmdate ("D، d M Y H: i: s"، time () + 86400 * 365). "GMT")؛ header ("Cache-Control: max-age =" + 86400 * 365) ؛

أو يمكنك تخزين المحتوى مؤقتًا لفترة طويلة باستخدام mod_header في Apache:

بعد تلقي هذه الرؤوس ، سيقوم المتصفح بتخزين المستند مؤقتًا لفترة طويلة. سيتم تقديم جميع المكالمات الأخرى إلى المستند مباشرة من ذاكرة التخزين المؤقت للمتصفح ، دون الاتصال بالخادم.

لا تقوم معظم المتصفحات (Opera ، Internet Explorer 6+ ، Safari) بتخزين المستندات مؤقتًا إذا كانت هناك علامة استفهام في العنوان ، لأنها تعتبر ديناميكية.

هذا هو سبب إضافة الإصدار إلى اسم الملف. بالطبع ، مع هذه العناوين ، يجب عليك استخدام حل مثل mod_rewrite ، سننظر في هذا لاحقًا في المقالة.

ملاحظة لكن Firefox يخزن العناوين بعلامات استفهام ..

ترجمة تلقائية للاسم

دعونا نرى كيفية تغيير الإصدارات تلقائيًا وشفافًا دون إعادة تسمية الملفات نفسها.

اسم الإصدار -> ملف

أبسط شيء هو تحويل اسم الإصدار إلى اسم الملف الأصلي.

على مستوى Apache ، يمكن القيام بذلك باستخدام mod_rewrite:

أعد كتابة المحرك على قاعدة الكتابة ^ / (. * \.) V + \. (Css | js | gif | png | jpg) $ / $ 1 $ 2 [L]

تعالج هذه القاعدة جميع ملفات css / js / gif / png / jpg ، وتجرد الإصدار من الاسم.

على سبيل المثال:

/images/logo.v2.gif -> /images/logo.gif
/css/style.v1.27.css -> /css/style.css
/javascript/script.v6.js -> /javascript/script.js

ولكن بالإضافة إلى قص الإصدار ، تحتاج أيضًا إلى إضافة رؤوس مخزنة مؤقتًا إلى الملفات. لهذا ، يتم استخدام توجيهات mod_header:

إضافة الرأس "Expires" "الإثنين ، 28 يوليو 2014 23:30:00 GMT" رأس إضافة "Cache-Control" "max-age = 315360000"

وكلها تقوم بتنفيذ مثل هذا التكوين اباتشي:

يزيل RewriteEngine on # الإصدار ، وفي نفس الوقت يعيّن المتغير الذي يحمل الملف إصدار RewriteRule ^ / (. * \.) V + \. (Css | js | gif | png | jpg) $ / $ 1 $ 2 # hard-cache version files Header إضافة "Expires" الاثنين ، 28 يوليو 2014 23:30:00 GMT "env = VERSIONED_FILE Header إضافة" Cache-Control "" max-age = 315360000 "env = VERSIONED_FILE

نظرًا للطريقة التي تعمل بها الوحدة النمطية mod_rewrite ، يجب وضع RewriteRule في ملف التكوين الرئيسي httpd.conf أو في الملفات المتصلة به ، ولكن ليس بأي حال من الأحوال في .htaccess ، وإلا فسيتم تشغيل أوامر Header أولاً ، قبل أن يتم متغير مثبت VERSIONED_FILE.

يمكن أن تكون توجيهات الرأس في أي مكان ، حتى في .htaccess - لا فرق.

قم تلقائيًا بإضافة إصدار إلى اسم الملف في صفحة HTML

تعتمد كيفية وضع إصدار في اسم البرنامج النصي على نظام القوالب الخاص بك ، وبشكل عام ، كيفية إضافة البرامج النصية (الأنماط ، وما إلى ذلك).

على سبيل المثال ، عند استخدام تاريخ التعديل كإصدار ومحرك قالب Smarty ، يمكن تعيين الروابط على النحو التالي:

تضيف وظيفة الإصدار إصدارًا:

الوظيفة smarty_version ($ args) ($ stat = stat ($ GLOBALS ["config"] ["site_root"]. $ Args ["src"]) ؛ $ version = $ stat ["mtime"] ؛ echo preg_replace ("! \. (+؟) $! "،" .v $ version. \ $ 1 "، $ args [" src "])؛)

النتيجة في الصفحة:

الاقوي

لتجنب استدعاءات الإحصائيات غير الضرورية ، يمكنك تخزين مصفوفة تسرد الإصدارات الحالية في متغير منفصل.

إصدارات $ ["css"] = array ("group.css" => "1.1"، "other.css" => "3.0"،)

في هذه الحالة ، يتم استبدال HTML ببساطة بالإصدار الحالي من المصفوفة.

يمكنك تجاوز كلا النهجين ، وإصدار إصدار حسب تاريخ التعديل أثناء التطوير - من أجل الصلة ، وفي الإنتاج - إصدار من مصفوفة للأداء.

القابلية للتطبيق

تعمل طريقة التخزين المؤقت هذه في كل مكان ، بما في ذلك Javascript و CSS والصور وأفلام الفلاش وما إلى ذلك.

يكون مفيدًا عندما يتغير المستند ، ولكن يجب أن يحتوي المتصفح دائمًا على الإصدار الحالي.