javascript - हणज - कैश किए गए सीएसएस/जेएस फ़ाइलों को फिर से लोड करने के लिए ब्राउज़र को कैसे मजबूर करें?




प्रपत्र एचटीएमएल (20)

मैंने देखा है कि कुछ ब्राउज़रों (विशेष रूप से, फ़ायरफ़ॉक्स और ओपेरा) ब्राउज़र सत्रों के बीच भी .css और .js फ़ाइलों की कैश की गई प्रतियों का उपयोग करने में बहुत उत्साही हैं। यह एक समस्या का कारण बनता है जब आप इन फ़ाइलों में से किसी एक को अपडेट करते हैं लेकिन उपयोगकर्ता का ब्राउज़र कैश की गई प्रति का उपयोग करता रहता है।

सवाल यह है कि उपयोगकर्ता के ब्राउजर को फ़ाइल को फिर से लोड करने के लिए मजबूर करने का सबसे शानदार तरीका क्या है?

आदर्श रूप से समाधान पृष्ठ पर प्रत्येक विज़िट पर फ़ाइल को पुनः लोड करने के लिए ब्राउज़र को मजबूर नहीं करेगा। मैं अपना खुद का समाधान उत्तर के रूप में पोस्ट करूंगा, लेकिन अगर कोई बेहतर समाधान कर रहा है तो मैं उत्सुक हूं और मैं आपके वोटों को तय करूंगा।

अद्यतन करें:

थोड़ी देर के लिए यहां चर्चा की अनुमति देने के बाद, मुझे जॉन मिलिकिन और दा 5id के सुझाव उपयोगी होने के लिए मिला है। यह पता चला है कि इसके लिए एक शब्द है: ऑटो-वर्जनिंग

मैंने नीचे एक नया उत्तर पोस्ट किया है जो मेरे मूल समाधान और जॉन के सुझाव का संयोजन है।

एससीडीएफ द्वारा सुझाए गए एक अन्य विचार को फ़ाइल में एक फर्जी क्वेरी स्ट्रिंग जोड़ना होगा। (कुछ पायथन कोड स्वचालित रूप से टाइमस्टैम्प का उपयोग करने के लिए एक फर्जी क्वेरी स्ट्रिंग के रूप में पीआई द्वारा प्रस्तुत किया गया था।)। हालांकि, कुछ चर्चा है कि ब्राउजर क्वेरी स्ट्रिंग वाले फ़ाइल को कैश करेगा या नहीं। (याद रखें, हम चाहते हैं कि ब्राउजर फ़ाइल को कैश करे और भविष्य में विज़िट पर इसका इस्तेमाल करे। हम केवल यह बदलना चाहते हैं कि फ़ाइल को फिर से बदलना पड़े।)

चूंकि यह स्पष्ट नहीं है कि एक फर्जी क्वेरी स्ट्रिंग के साथ क्या होता है, मैं उस उत्तर को स्वीकार नहीं कर रहा हूं।


ASP.NET 4.5 और अधिक के लिए आप स्क्रिप्ट बंडलिंग का उपयोग कर सकते हैं।

अनुरोध http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81 बंडल ऑलमैंक के लिए है और इसमें क्वेरी स्ट्रिंग जोड़ी v = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81 शामिल है। क्वेरी स्ट्रिंग वी में एक मान टोकन है जो कैशिंग के लिए उपयोग किया जाने वाला एक अद्वितीय पहचानकर्ता है। जब तक बंडल नहीं बदलता है, तब तक एएसपी.NET एप्लिकेशन इस टोकन का उपयोग करके ऑलमीकन बंडल का अनुरोध करेगा। यदि बंडल में कोई भी फ़ाइल बदलती है, तो एएसपी.नेट अनुकूलन ढांचा एक नया टोकन उत्पन्न करेगा, गारंटी देता है कि बंडल के लिए ब्राउज़र अनुरोध नवीनतम बंडल प्राप्त करेंगे।

खनन के साथ पहली बार पेज लोड पर बढ़े हुए प्रदर्शन सहित बंडल करने के अन्य लाभ भी हैं।


Foo.css? संस्करण = 1 का उपयोग न करें! ब्राउजर को GET चर के साथ यूआरएल कैश नहीं करना चाहिए। http://www.thinkvitamin.com/features/webapps/serving-javascript-fast अनुसार, हालांकि आईई और फ़ायरफ़ॉक्स इसे अनदेखा करते हैं, ओपेरा और सफारी नहीं करते हैं! इसके बजाय, foo.v1234.css का उपयोग करें, और संस्करण संख्या को बाहर निकालने के लिए नियमों को फिर से लिखें।


अपाचे के लिए Google की mod_pagespeed प्लगइन आपके लिए ऑटो-वर्जनिंग करेगा। यह वास्तव में चालाक है।

यह वेबसर्वर (PHP, रेल, पायथन, स्थिर एचटीएमएल - कुछ भी के साथ काम करता है) के माध्यम से एचटीएमएल को पार करता है और सीएसएस, जेएस, छवि फ़ाइलों के लिंक को फिर से लिखता है ताकि उनमें एक आईडी कोड शामिल हो। यह संशोधित यूआरएल पर फाइलों को बहुत लंबे कैश नियंत्रण के साथ पेश करता है। जब फ़ाइलें बदलती हैं, तो यह स्वचालित रूप से यूआरएल को बदल देती है ताकि ब्राउज़र को उन्हें फिर से प्राप्त करना पड़े। यह मूल रूप से बस आपके कोड में किसी भी बदलाव के बिना काम करता है। यह आपके कोड को रास्ते में भी छोटा कर देगा।


आप बस अपने सीएसएस / जेएस आयात के अंत में ?foo=1234 डाल सकते हैं, जो भी आपको पसंद हो, 1234 बदलना। उदाहरण के लिए SO HTML स्रोत पर एक नज़र डालें।

विचार यह है कि? पैरामीटर को अनुरोध पर त्याग दिया / अनदेखा किया जाता है और जब आप एक नया संस्करण रोल करते हैं तो आप उस नंबर को बदल सकते हैं।

नोट: कैशिंग को प्रभावित करने के तरीके के संबंध में कुछ तर्क है। मेरा मानना ​​है कि इसका सामान्य ज्ञान यह है कि अनुरोध प्राप्त करें, पैरामीटर के साथ या बिना कैशबल होना चाहिए, इसलिए उपरोक्त समाधान को काम करना चाहिए।

हालांकि, यह तय करने के लिए दोनों वेब सर्वर पर निर्भर है कि क्या वह स्पेक के उस हिस्से और उपयोगकर्ता द्वारा उपयोग किए जाने वाले ब्राउज़र का पालन करना चाहता है, क्योंकि यह अभी आगे बढ़ सकता है और फिर भी एक नया संस्करण मांग सकता है।


एएसपी.नेट के लिए मुझे लगता है कि उन्नत विकल्प (डीबग / रिलीज मोड, संस्करण) के साथ अगला समाधान:

जेएस या सीएसएस फाइलें इस तरह से शामिल हैं:

<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();
    }
    ...
}

क्लाइंट पक्षीय DOM दृष्टिकोण को स्क्रिप्ट नोड (या सीएसएस) तत्व को गतिशील रूप से नहीं मिला है:

<script>
    var node = document.createElement("script"); 
    node.type = "text/javascript";
    node.src = 'test.js?'+Math.floor(Math.random()*999999999);
    document.getElementsByTagName("head")[0].appendChild(node);
</script>

निश्चित नहीं है कि आप इस समाधान को लागू करने के लिए लोग इतने दर्द क्यों ले रहे हैं।

फ़ाइल की संशोधित टाइमस्टैंप प्राप्त करने और फ़ाइल में क्वेरीस्ट्रिंग के रूप में इसे जोड़ने के लिए आपको बस इतना करना होगा

PHP में मैं इसे इस प्रकार करूँगा:

<link rel="stylesheet" href="mycss.css?v=<?php echo filemtime('mycss.css') ?>"/>

filemtime एक PHP फ़ंक्शन है जो फ़ाइल संशोधित टाइमस्टैम्प देता है।


मान लें कि आपके पास एक फ़ाइल उपलब्ध है:

/styles/screen.css

आप या तो यूआरआई पर संस्करण जानकारी के साथ एक क्वेरी पैरामीटर जोड़ सकते हैं, उदाहरण के लिए:

/styles/screen.css?v=1234

या आप संस्करण की जानकारी पूर्ववत कर सकते हैं, उदाहरण के लिए:

/v/1234/styles/screen.css

आईएमएचओ दूसरी विधि सीएसएस फाइलों के लिए बेहतर है क्योंकि वे रिश्तेदार यूआरएल का उपयोग कर छवियों को संदर्भित कर सकते हैं जिसका मतलब है कि यदि आप background-image निर्दिष्ट करते हैं तो:

body {
    background-image: url('images/happy.gif');
}

इसका यूआरएल प्रभावी ढंग से होगा:

/v/1234/styles/images/happy.gif

इसका अर्थ यह है कि यदि आप संस्करण संख्या को अद्यतन करते हैं तो सर्वर इसे एक नए संसाधन के रूप में पेश करेगा और कैश किए गए संस्करण का उपयोग नहीं करेगा। यदि आप सबवर्सन / सीवीएस / आदि पर अपना संस्करण नंबर आधार करते हैं। संशोधन का मतलब है कि सीएसएस फाइलों में संदर्भित छवियों में परिवर्तनों पर ध्यान दिया जाएगा। यह पहली योजना के साथ गारंटी नहीं है, यानी URL images/happy.gif सापेक्ष /styles/screen.css?v=1235 है जिसमें कोई संस्करण जानकारी नहीं है।

मैंने जावा सर्लेट के साथ इस तकनीक का उपयोग करके एक कैशिंग समाधान लागू किया है और अंतर्निहित संसाधन (यानी /styles/screen.css ) को /styles/screen.css करने वाले सर्वलेट के साथ /v/* अनुरोधों को आसानी से संभाल /styles/screen.css । विकास मोड में मैंने कैशिंग हेडर सेट किए हैं जो क्लाइंट को हमेशा सर्वर के साथ संसाधन की ताजगी की जांच करने के लिए कहते हैं (यदि आप टॉमकैट के DefaultServlet और .css , .js , आदि को प्रतिनिधि करते हैं तो यह आम तौर पर 304 में होता है। फ़ाइल बदल नहीं है ) जबकि तैनाती मोड में मैंने हेडर सेट किया जो "हमेशा के लिए कैश" कहता है।


मैंने हाल ही में पायथन का उपयोग करके हल किया है। यहां कोड (अन्य भाषाओं को अपनाने में आसान होना चाहिए):

def import_tag(pattern, name, **kw):
    if name[0] == "/":
        name = name[1:]
    # Additional HTML attributes
    attrs = ' '.join(['%s="%s"' % item for item in kw.items()])
    try:
        # Get the files modification time
        mtime = os.stat(os.path.join('/documentroot', name)).st_mtime
        include = "%s?%d" % (name, mtime)
        # this is the same as sprintf(pattern, attrs, include) in other
        # languages
        return pattern % (attrs, include)
    except:
        # In case of error return the include without the added query
        # parameter.
        return pattern % (attrs, name)

def script(name, **kw):
    return import_tag("""<script type="text/javascript" """ +\
        """ %s src="/%s"></script>""", name, **kw)

def stylesheet(name, **kw):
    return import_tag('<link rel="stylesheet" type="text/css" ' +\
        """%s href="/%s">', name, **kw) 

This code basically appends the files time-stamp as a query parameter to the URL. The call of the following function

script("/main.css")

will result in

<link rel="stylesheet" type="text/css"  href="/main.css?1221842734">

The advantage of course is that you do never have to change your html again, touching the CSS file will automatically trigger a cache invalidation. Works very good and the overhead is not noticeable.


मैन्युअल रूप से संस्करण को बदलने के बजाय, मैं आपको वास्तविक सीएसएस फ़ाइल के एमडी 5 हैश का उपयोग करने की सलाह दूंगा।

तो आपका यूआरएल कुछ ऐसा होगा

http://mysite.com/css/[md5_hash_here]/style.css

आप अभी भी हैश को बाहर निकालने के लिए पुनर्लेखन नियम का उपयोग कर सकते हैं, लेकिन लाभ यह है कि अब आप अपनी कैश नीति को "हमेशा के लिए कैश" पर सेट कर सकते हैं, क्योंकि यदि यूआरएल समान है, तो इसका मतलब है कि फ़ाइल अपरिवर्तित है।

फिर आप एक साधारण शेल स्क्रिप्ट लिख सकते हैं जो फ़ाइल के हैश की गणना करेगा और आपके टैग को अपडेट करेगा (आप शायद इसे शामिल करने के लिए एक अलग फ़ाइल में ले जाना चाहते हैं)।

प्रत्येक बार सीएसएस में बदलाव होने पर बस उस स्क्रिप्ट को चलाएं और आप अच्छे हैं। जब ब्राउज़र बदल दिया जाता है तो ब्राउज़र केवल आपकी फ़ाइलों को पुनः लोड करेगा। यदि आप एक संपादन करते हैं और फिर इसे पूर्ववत करते हैं, तो यह पता लगाने में कोई दिक्कत नहीं है कि आपके विज़िटर को फिर से डाउनलोड न करने के लिए आपको किस संस्करण को वापस करने की आवश्यकता है।


यहां एक शुद्ध जावास्क्रिप्ट समाधान है

(function(){

    // Match this timestamp with the release of your code
    var lastVersioning = Date.UTC(2014, 11, 20, 2, 15, 10);

    var lastCacheDateTime = localStorage.getItem('lastCacheDatetime');

    if(lastCacheDateTime){
        if(lastVersioning > lastCacheDateTime){
            var reload = true;
        }
    }

    localStorage.setItem('lastCacheDatetime', Date.now());

    if(reload){
        location.reload(true);
    }

})();

उपरोक्त आखिरी बार उपयोगकर्ता आपकी साइट पर आएगा। यदि अंतिम कोड आपको नया कोड जारी करने से पहले था, तो यह सर्वर से पेज रीफ्रेश को मजबूर करने के लिए location.reload(true) का उपयोग करता है।

मेरे पास आमतौर पर <head> भीतर पहली स्क्रिप्ट के रूप में होता है, इसलिए इसका मूल्यांकन किसी अन्य सामग्री लोड से पहले किया जाता है। यदि एक रीलोड होने की आवश्यकता है, तो यह उपयोगकर्ता के लिए शायद ही ध्यान देने योग्य है।

मैं ब्राउज़र पर अंतिम विज़िट टाइमस्टैम्प स्टोर करने के लिए स्थानीय संग्रहण का उपयोग कर रहा हूं, लेकिन यदि आप IE के पुराने संस्करणों का समर्थन करना चाहते हैं तो आप मिश्रण में कुकीज़ जोड़ सकते हैं।


रिवाइटरूल को जेएस या सीएसएस फाइलों के लिए एक छोटे से अपडेट की आवश्यकता होती है जिसमें अंत में एक डॉट नोटेशन संस्करण होता है। जैसे जेसन-1.3.जेएस।

मैंने रेगिक्स में एक डॉट अस्वीकरण वर्ग [^।] जोड़ा। संख्या। अनदेखा किया जाता है।

RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]

लार्वेल (PHP) में हम इसे स्पष्ट और सुरुचिपूर्ण तरीके से पालन कर सकते हैं (फ़ाइल संशोधन टाइमस्टैम्प का उपयोग करके):

<script src="{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>

और सीएसएस के लिए समान है

<link rel="stylesheet" href="{{asset('css/your.css?v='.filemtime('css/your.css'))}}">

अद्यतन: जॉन मिलिकिन और दा 5id से सुझावों को शामिल करने के लिए लिखा गया। यह समाधान PHP में लिखा गया है, लेकिन इसे अन्य भाषाओं में आसानी से अनुकूलित किया जाना चाहिए।

अद्यतन 2: निक जॉनसन से टिप्पणियां शामिल करना जो मूल .htaccess regex json-1.3.js जैसी फ़ाइलों के साथ समस्याएं पैदा कर सकता है। समाधान केवल तभी लिखना है जब अंत में बिल्कुल 10 अंक हों। (क्योंकि 10 अंकों में 9/9/2001 से 11/20/2286 तक सभी टाइमस्टैम्प शामिल हैं।)

सबसे पहले, हम .htaccess में निम्न पुनर्लेखन नियम का उपयोग करते हैं:

RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]

अब, हम निम्नलिखित PHP फ़ंक्शन लिखते हैं:

/**
 *  Given a file, i.e. /css/base.css, replaces it with a string containing the
 *  file's mtime, i.e. /css/base.1221534296.css.
 *  
 *  @param $file  The file to be loaded.  Must be an absolute path (i.e.
 *                starting with slash).
 */
function auto_version($file)
{
  if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
    return $file;

  $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
  return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $file);
}

अब, जहां भी आप अपना सीएसएस शामिल करते हैं, इसे इस से बदलें:

<link rel="stylesheet" href="/css/base.css" type="text/css" />

इसके लिए:

<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />

इस तरह, आपको लिंक टैग को फिर से संशोधित नहीं करना होगा, और उपयोगकर्ता हमेशा नवीनतम सीएसएस देखेंगे। ब्राउज़र सीएसएस फ़ाइल को कैश करने में सक्षम होगा, लेकिन जब आप अपने सीएसएस में कोई बदलाव करेंगे तो ब्राउज़र इसे एक नए यूआरएल के रूप में देखेगा, इसलिए यह कैश की गई प्रति का उपयोग नहीं करेगा।

यह छवियों, फेविकॉन, और जावास्क्रिप्ट के साथ भी काम कर सकता है। मूल रूप से कुछ भी जो गतिशील रूप से उत्पन्न नहीं होता है।



I put an MD5 hash of the file's contents in its URL. That way I can set a very long expiration date, and don't have to worry about users having old JS or CSS.

I also calculate this once per file at runtime (or on file system changes) so there's nothing funny to do at design time or during the build process.

If you're using ASP.NET MVC then you can check out the code in my other answer here .


I'm adding this answer as a SilverStripe http://www.silverstripe.org specific answer which I was looking for and never found but have worked out from reading: http://api.silverstripe.org/3.0/source-class-SS_Datetime.html#98-110

Hopefully this will help someone using a SilverStripe template and trying to force reload a cached image on each page visit / refresh. In my case it is a gif animation which only plays once and therefor did not replay after it was cached. In my template I simply added:

?$Now.Format(dmYHis)

to the end of the file path to create a unique time stamp and to force the browser to treat it as a new file.



Sorry for bringing back a dead thread.

@ TomA is right.

Using "querystring" method will not be cached as quoted by Steve Souders below:

...that Squid, a popular proxy, doesn't cache resources with a querystring.

@ TomA suggestion of using style.TIMESTAMP.css is good, but MD5 would be much better as only when the contents were genuinely changed, the MD5 changes as well.


google chrome has Hard Reload as well as Empty Cache and Hard Reload option.You can click and hold the reload button (In Inspect Mode) to select one .





auto-versioning