كيف يمكنني إجبار العملاء على تحديث ملفات JavaScript؟

StackOverflow https://stackoverflow.com/questions/32414

  •  09-06-2019
  •  | 
  •  

سؤال

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

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

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

هل كانت مفيدة؟

المحلول

بقدر ما أعرف الحل المشترك هو إضافة ملف ?<version> إلى رابط src للبرنامج النصي.

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

<script type="text/javascript" src="myfile.js?1500"></script>

أفترض في هذه المرحلة أنه لا توجد طريقة أفضل من البحث والاستبدال لزيادة "أرقام الإصدارات" هذه في جميع علامات البرنامج النصي؟

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

سيبدو شيء هكذا:

<script type="text/javascript" src="myfile.js?$$REVISION$$"></script>

وبطبيعة الحال، هناك دائما حلول أفضل مثل هذا.

نصائح أخرى

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

على سبيل المثال، لفرض تخزين الملف مؤقتًا لمدة لا تزيد عن يوم واحد، يمكنك إرسال:

Cache-Control: max-age=86400, must-revalidate

بالنسبة للإصدار التجريبي، إذا كنت تريد إجبار المستخدم على الحصول دائمًا على الأحدث، فيمكنك استخدام:

Cache-Control: no-cache, must-revalidate

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

في هذه الحالة، يمكنك تضمين الإصدار في عنوان URL، على سبيل المثال: http://abc.com/v1.2/script.js واستخدم Apache mod_rewrite لإعادة توجيه الرابط إليه http://abc.com/script.js.عندما تقوم بتغيير الإصدار، سيقوم متصفح العميل بتحديث الملف الجديد.

لقد تم إهمال هذا الاستخدام: https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache

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

CACHE MANIFEST
# Aug 14, 2014
/mycode.js

NETWORK:
*

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

ماذا عن إضافة الملف كمعلمة تحميل؟

<script type='text/javascript' src='path/to/file/mylibrary.js?filever=<?=filesize('path/to/file/mylibrary.js')?>'></script>

لذلك في كل مرة تقوم فيها بتحديث الملف، تتغير معلمة "filever".

ماذا لو قمت بتحديث الملف ونتج عن التحديث نفس حجم الملف؟ما هي احتمالات؟

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

لذلك بدلا من stuff.js?123, ، فعلتُ stuff_123.js

إستعملت mod_redirect(على ما أظن) في اباتشي ل have stuff_*.js توجو stuff.js

بالنسبة لصفحات ASP.NET أستخدم ما يلي

قبل

<script src="/Scripts/pages/common.js" type="text/javascript"></script>

بعد (إعادة تحميل القوة)

<script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

تعمل إضافة DateTime.Now.Ticks بشكل جيد جدًا.

بالنسبة لـ ASP.NET، أفترض أن الحل التالي يتضمن خيارات متقدمة (وضع التصحيح/الإصدار، الإصدارات):

يتم تضمين ملفات Js أو Css بهذه الطريقة:

<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />

يتم حساب Global.JsPostfix وGlobal.CssPostfix بالطريقة التالية في Global.asax:

protected void Application_Start(object sender, EventArgs e)
{
    ...
    string jsVersion = ConfigurationManager.AppSettings["JsVersion"];
    bool updateEveryAppStart = Convert.ToBoolean(ConfigurationManager.AppSettings["UpdateJsEveryAppStart"]);
    int buildNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision;
    JsPostfix = "";
#if !DEBUG
    JsPostfix += ".min";
#endif      
    JsPostfix += ".js?" + jsVersion + "_" + buildNumber;
    if (updateEveryAppStart)
    {
        Random rand = new Random();
        JsPosfix += "_" + rand.Next();
    }
    ...
}

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

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

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

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

رابط البرنامج النصي المقدم للمستخدم

<script src="https://thesaasdomain.com/somejsfile.js" data-ut="user_token"></script>

ملف البرنامج النصي

if($('script[src^="https://thesaasdomain.com/somejsfile.js?"]').length !== 0) {
   init();
} else {
   loadScript("https://thesaasdomain.com/somejsfile.js?" + guid());
}

var loadscript = function(scriptURL) {
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = scriptURL;
   head.appendChild(script);
}

var guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

var init = function() {
    // our main code
}

توضيح:

قام المستخدم بإرفاق البرنامج النصي المقدم له في موقعه على الويب وتحققنا من وجود الرمز الفريد المرفق مع البرنامج النصي أو عدم استخدام محدد jQuery وإذا لم يكن الأمر كذلك، فقم بتحميله ديناميكيًا باستخدام الرمز المميز (أو الإصدار الأحدث)

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

تنصل:لا تستخدمه إذا كان الأداء يمثل مشكلة كبيرة في حالتك.

يمكن أيضًا استخدام دالة jQuery getScript للتأكد من تحميل ملف js بالفعل في كل مرة يتم فيها تحميل الصفحة.

هذه هي الطريقة التي فعلت ذلك:

$(document).ready(function(){
    $.getScript("../data/playlist.js", function(data, textStatus, jqxhr){
         startProgram();
    });
});

تحقق من الوظيفة في http://api.jquery.com/jQuery.getScript/

افتراضيًا، يقوم $.getScript() بتعيين إعداد ذاكرة التخزين المؤقت على false.يؤدي هذا إلى إلحاق معلمة استعلام ذات طابع زمني بعنوان URL للطلب للتأكد من أن المتصفح يقوم بتنزيل البرنامج النصي في كل مرة يتم طلبه فيها.

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

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

يبدو أن الحل الأكثر شيوعًا هو تضمين طابع زمني أو رقم مراجعة في اسم الملف نفسه.هذا يتطلب المزيد من العمل، لأن الكود الخاص بك يحتاج إلى تعديل لطلب الملفات الصحيحة، ولكنه يعني ذلك، على سبيل المثال.الإصدار 7 الخاص بك snazzy_javascript_file.js (أي. snazzy_javascript_file_7.js) يتم تخزينه مؤقتًا على المتصفح حتى تقوم بإصدار الإصدار 8، ثم يتغير الكود الخاص بك ليتم جلبه snazzy_javascript_file_8.js بدلاً من.

استخدم نسخة GET متغير لمنع التخزين المؤقت للمتصفح.

إلحاق ?v=AUTO_INCREMENT_VERSION إلى نهاية عنوان URL الخاص بك يمنع التخزين المؤقت للمتصفح - مع تجنب أي وجميع البرامج النصية المخزنة مؤقتًا.

لقد عثر زميلي للتو على إشارة إلى هذه الطريقة مباشرة بعد أن قمت بالنشر (في إشارة إلى CSS) على http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/.من الجيد أن نرى أن الآخرين يستخدمونه ويبدو أنه يعمل.أفترض في هذه المرحلة أنه لا توجد طريقة أفضل من البحث والاستبدال لزيادة "أرقام الإصدارات" هذه في جميع علامات البرنامج النصي؟

على الرغم من أنه إطار عمل محدد، فإن Django 1.4 لديه هذه الوظيفة والذي يعمل بطريقة مشابهة للرابط الخاص بموقع "greenfelt" في فوق الجواب

في بي أتش بي:

function latest_version($file_name){
    echo $file_name."?".filemtime($_SERVER['DOCUMENT_ROOT'] .$file_name);
}

في لغة البرمجة:

<script type="text/javascript" src="<?php latest_version('/a-o/javascript/almanacka.js'); ?>">< /script>

كيف تعمل:

في HTML، اكتب filepath والاسم كما تريد، ولكن في الوظيفة فقط.PHP يحصل على filetime من الملف وإرجاع filepath+name+"?"+time من أحدث التغيير

سوف يتعامل خرق ذاكرة التخزين المؤقت في ASP.NET Core عبر مساعد العلامات مع هذا الأمر نيابةً عنك ويسمح للمتصفح الخاص بك بالاحتفاظ بالبرامج النصية/css المخزنة مؤقتًا حتى يتغير الملف.ما عليك سوى إضافة مساعد العلامات asp-append-version="true" إلى علامة البرنامج النصي (js) أو علامة الارتباط (css):

<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true"/>

لدى Dave Paquette مثال جيد وشرح لخرق ذاكرة التخزين المؤقت هنا (أسفل الصفحة) خرق ذاكرة التخزين المؤقت

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

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

بائع.a7561fb0e9a071baadb9.js
رئيسي.b746e3eb72875af2caa9.js

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

أبسط حل؟لا تدع ذاكرة التخزين المؤقت للمتصفح على الإطلاق.إلحاق الوقت الحالي (بالمللي ثانية) كاستعلام.

(أنت لا تزال في مرحلة تجريبية، لذا يمكنك تقديم حجة معقولة لعدم تحسين الأداء.لكن YMMV هنا.)

ميزة استخدام أ file.js?V=1 أكثر من fileV1.js هو أنك لا تحتاج إلى تخزين إصدارات متعددة من ملفات JavaScript على الخادم.

المشكلة التي أرى معها file.js?V=1 هو أنه قد يكون لديك تعليمات برمجية تابعة في ملف JavaScript آخر ينقطع عند استخدام الإصدار الجديد من أدوات المكتبة المساعدة.

من أجل التوافق مع الإصدارات السابقة، أعتقد أنه من الأفضل استخدامه jQuery.1.3.js لصفحاتك الجديدة والسماح باستخدام الصفحات الحالية jQuery.1.1.js, ، حتى تصبح جاهزًا لترقية الصفحات القديمة، إذا لزم الأمر.

طريقة واحدة بسيطة.تحرير هتكس

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} \.(jpe?g|bmp|png|gif|css|js|mp3|ogg)$ [NC]
RewriteCond %{QUERY_STRING} !^(.+?&v33|)v=33[^&]*(?:&(.*)|)$ [NC]
RewriteRule ^ %{REQUEST_URI}?v=33 [R=301,L]

في asp.net mvc يمكنك استخدامه @DateTime.UtcNow.ToString() لرقم إصدار ملف js.يتغير رقم الإصدار تلقائيًا مع التاريخ وتجبر متصفح العملاء على تحديث ملف js تلقائيًا.أنا أستخدم هذه الطريقة وهذا يعمل بشكل جيد.

<script src="~/JsFilePath/JsFile.js?v=@DateTime.UtcNow.ToString()"></script>

عملت أدناه بالنسبة لي:

<head>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0" />
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
</head>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top