Parametreler aracılığıyla önbellek bozma


123

Üretim dağıtımlarında çöküşü önbelleğe almak istiyoruz, ancak bunu yapmak için bir sistem bulmak için yarasadan çok fazla zaman harcamamak istiyoruz. Benim düşüncem css ve js dosyalarının sonuna mevcut sürüm numarasıyla bir parametre uygulamaktı:

<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>

İki soru: Bu, önbelleği etkili bir şekilde kırar mı? Param, tarayıcının bu url'den gelen yanıtı asla önbelleğe almamasına neden olur, çünkü param bunun dinamik içerik olduğunu gösterir mi?

Yanıtlar:


115

Param ?v=1.123, bir sorgu dizesini belirtir ve bu nedenle tarayıcı, örneğin, bunun yeni bir yol olduğunu düşünecektir ?v=1.0. Böylece önbellekten değil dosyadan yüklenmesine neden olur. İstediğin gibi.

Ve, tarayıcı kaynak aramak aynı dahaki sefere kalacak üstlenecek ?v=1.123ve gerektiği bu dize ile önbelleğe. Böylece, siz taşınana kadar sunucunuz kurulu olsa da önbelleğe alınmış olarak kalacaktır ?v=1.124.


4
Steve Souders'den alıntı: "Popüler proxy'ler tarafından önbelleğe alma avantajından yararlanmak için, sorgu dizesi ile devir yapmaktan kaçının ve bunun yerine dosya adının kendisini revize edin." Tam açıklamayı burada bulabilirsiniz: stevesouders.com/blog/2008/08/23/…
lao

25
Bu blog yazısı şimdi on yıl öncesine yaklaşıyor. Önbellek sağlayıcılarının ve CDN'lerin henüz buna uyum sağlamadığını düşünüyor musunuz? Squid artık belgeleri sorgu dizeleriyle önbelleğe alabilecek gibi görünüyor .
jeteon

1
Belki bu birisine yardımcı olur: Kişisel olarak, dosya değiştirme zaman damgasını 'otomatik' sürüm parametresi olarak kullanıyorum, örn. <link rel="stylesheet" href="style.css?v=1487935578" />
oelna

Nedenini şahsen anlamıyorum, ancak Lara Hogan (Swanson) (Etsy'deki mühendislik yöneticisi) önbellek bozmak için sorgu parametrelerinin kullanılmasını önermiyor. Bence kullanıcı ve sunucu arasındaki önbellek proxy'leri ile ilgisi var.
Sam Rueby

36

İki soru: Bu, önbelleği etkili bir şekilde kırar mı?

Evet. Stack Overflow bile bu yöntemi kullanıyor, ancak onların (her gün milyonlarca ziyaretçisi ve zilyonlarca farklı istemci ve proxy sürümleri ve yapılandırmalarıyla) önbelleği kırmak için bunun bile yeterli olmadığı bazı acayip uç durumlar yaşadıklarını hatırlıyorum. Ancak genel varsayım, bunun işe yarayacağı ve istemcilerde önbelleğe almayı bozmak için uygun bir yöntem olduğudur.

Param, tarayıcının bu url'den gelen yanıtı asla önbelleğe almamasına neden olur, çünkü param bunun dinamik içerik olduğunu gösterir mi?

Hayır. Parametre, önbelleğe alma politikasını değiştirmez; sunucu tarafından gönderilen önbelleğe alma başlıkları hala geçerlidir ve hiç göndermezse tarayıcının varsayılanları.


1
@spender Şu anda referansı bulamıyorum Korkarım, Jeff Atwood'un bahsettiği uzun bir blog makalesi ya da SO cevabı vardı (IIRC)
Pekka

2
@spender Bazı proxy sunucularının (eski veya yapılandırılabilir) önbelleğe alırken sorgu dizesini yok saydığını okudum.
MrWhite

2
@spender - Ben de aynı şeyi duydum ve bence dosya adını veya yolu değiştirmek en iyi seçenek. Tüm statik dosyalarınızı sürüme bağlı bir klasör adı altında taşımanıza izin vermek en kolayı olabilir, örneğin, /static/v22/file.csstek bir klasörü yeniden adlandırarak birden fazla dosya yapabileceğiniz için, örneğin /static/v23/file.cssve/static/v23/mystuff.js
Brad Parks

22

Sürüm numarasını gerçek dosya adına koymak daha güvenlidir. Bu, birden çok sürümün aynı anda var olmasına izin verir, böylece yeni bir sürümü kullanıma sunabilirsiniz ve eski sürümü isteyen önbelleğe alınmış HTML sayfaları hala mevcutsa, HTML'leriyle çalışan sürümü alacaktır.

İnternette herhangi bir yerde bulunan en büyük sürümlü dağıtımlardan birinde, jQuery'nin gerçek dosya adındaki sürüm numaralarını kullandığını ve herhangi bir özel sunucu tarafı mantığı olmadan birden çok sürümün güvenli bir şekilde birlikte var olmasına izin verdiğini unutmayın (her sürüm yalnızca farklı bir dosyadır).

Bu, yeni sayfalar ve yeni bağlantılı dosyalar (istediğiniz şey budur) dağıttığınızda önbelleği bir kez bozar ve o andan itibaren bu sürümler etkili bir şekilde önbelleğe alınabilir (ki bunu da isteyebilirsiniz).


Buna katılıyorum, ancak Sinatra'nın her dosyayı ayrı ayrı kontrol etmek yerine tüm css ve js isteklerine? V = <% = VERSION%> eklemesi çok daha kolay. Sonunda, tüm dosyaları önceden işleyecek ve sıkıştıracak ve aslında dosya adına bir sürüm # ekleyecek olan sinatra-assetpack'e geçeceğiz, bu da onları tek tek çok daha kolay kontrol etmemize izin verecek.
Brad Herman

1
% 10000 emin olmak istiyorsanız, dosya adına sürüm numarasını koymanın en güvenli çözüm olduğunu kabul ediyorum, ancak "aynı anda birden fazla sürümün var olması" argümanını izlemiyorum. Sorgu parametresine sahip bir URL, farklı bir sorgu parametresine sahip aynı URL'den farklıdır. Müşteri tarafından iki farklı kaynak olarak ele alınmalıdır; değilse, müşteri bozulur.
Pekka

2
@Pekka - sürüm numarası olayı aynı anda birden fazla sürümün var olmasına izin verebilir, ancak bu, sorgu parametresini doğru gerçek dosyayla eşleştirmek için sunucu işbirliğini gerektirir. OP'nin burada yaptığı şeyin bu olduğunu sanmıyorum ve dosya adını değiştirirken bu karmaşıklığın çok daha basit olmasını ve sunucu işbirliğine ihtiyaç duymaması için çok az neden var. Açıkçası ikisi de işe yarayabilir.
jfriend00

11

Diğerlerinin de söylediği gibi, bir sorgu parametresiyle önbellek bozma genellikle Kötü Fikir (tm) olarak kabul edilir ve uzun zamandır budur. Sürümü dosya adına yansıtmak daha iyidir. Html5 Boilerplate , diğerleri arasında sorgu dizesinin kullanılmamasını önerir .

Bununla birlikte, bir kaynağa atıfta bulunan gördüğüm tavsiyelerin hepsi, hikmetlerini Steve Souders'in 2008 tarihli bir makalesinden alıyor gibi görünüyor . Elde ettiği sonuçlar, vekillerin o zamanki davranışlarına dayanıyor ve bu günlerde alakalı olabilir veya olmayabilir. Yine de, daha güncel bilgilerin yokluğunda, dosya adını değiştirmek güvenli seçenektir.


9

Önbelleği bir kez bozar, istemci kaynağı indirdikten sonra diğer her yanıt, aşağıdaki durumlar haricinde istemci önbelleğinden sunulur:

  1. v parametresi güncellenir.
  2. müşteri önbelleğini temizler

6

Genel olarak bu iyi olmalıdır, ancak istek parametrelerini yok sayacak şekilde yapılandırılmış bir ara önbellek (proxy) varsa bunun çalışmaması mümkündür.

Örneğin, Akamai CDN aracılığıyla statik içerik sunuyorsanız, bu yöntemi kullanarak önbellek bozmayı önlemek için istek parametrelerini yok sayacak şekilde yapılandırılabilir.


5

Önbelleğe alma işleminizin ne kadar sağlam olmasını istediğinize çok bağlıdır. Örneğin, squid proxy sunucusu (ve muhtemelen diğerleri) varsayılan olarak bir sorgu dizesiyle sunulan URL'leri önbelleğe almıyor - en azından bu makale yazılırken yaptı. Gereksiz önbellek atlamalarına neden olan belirli kullanım durumlarına aldırış etmiyorsanız, sorgu parametreleriyle devam edin. Ancak , bu sorunu ortadan kaldıran dosya adı tabanlı önbellek bozma şeması kurmak çok kolaydır.


5
Steve Souders makalesinde bahsedilen kalamar proxy'si varsayılan önbelleğe alma politikasını değiştirdi. Sürüm 2.7'den (Mayıs 2008) ve sürüm 3.1'den (Mart 2010) itibaren, varsayılan davranış dinamik içeriği önbelleğe almaktır.
Josh Rack

5

(Dosya adı vs sorgu dizesi) 2 tekniklerin karşılaştırılması Bulunan burada :

Sorgu dizisi olarak sürümün iki sorunu vardır.

Birincisi, her zaman engellememiz gereken önbelleğe almayı uygulayan bir tarayıcı olmayabilir. Bazı (muhtemelen daha eski) proxy'lerin önbelleğe alma davranışları açısından sorgu dizesini göz ardı ettiği söylenir.

İkinci olarak, birden çok ön uç ve / veya birden çok arka uç sunucunuzun olduğu bazı daha karmaşık dağıtım senaryolarında, yükseltme anlık olmaktan çok daha fazlasını ifade eder. Varlıklarınızın hem eski hem de yeni sürümünü aynı anda sunabilmelisiniz. Örneğin, Google App Engine kullanırken bunun sizi nasıl etkilediğine bakın.


4

Benzer bir yaklaşım da htaccess mod_rewrite kullanmaktır. dosyaları sunarken yolun bir kısmını yok saymak . Hiçbir zaman önbelleğe alınmamış dizin sayfanız, dosyaların en son yolunu gösterir.

Geliştirme açısından, sürüm numarası için parametreler kullanmak kadar kolaydır, ancak dosya adı yaklaşımı kadar sağlamdır.

Sürüm numarası için yolun göz ardı edilen kısmını kullanın ve sunucu onu yok sayar ve önbelleğe alınmamış dosyayı sunar.

1.2.3/css/styles.csscss/styles.cssilk dizin htaccess dosyası tarafından soyulup yok sayıldığından beri aynı dosyayı sunar

Sürümü belirlenmiş dosyalar dahil

<?php
  $version = "1.2.3";
?>

<html>
  <head>
    <meta http-equiv="cache-control" content="max-age=0" />
    <meta http-equiv="cache-control" content="no-cache" />
    <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" />
    <link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
  </head>
  <body>
    <script src="<?php echo $version ?>/js/main.js"></script>
  </body>
</html>

Bu yaklaşımın, dizin sayfanızın önbelleğe alınmasını devre dışı bırakmanız gerektiği anlamına geldiğini unutmayın - Tüm tarayıcılarda önbelleğe almayı kapatmak için <meta> etiketlerini mi kullanıyorsunuz?

.htaccess dosyası

RewriteEngine On

# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f 
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d 

# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L] 

Url'nin yeniden yazılmasına izin veren herhangi bir sunucu platformunda aynı yaklaşımı uygulayabilirsiniz

( mod_rewrite'dan uyarlanan koşulu yeniden yaz - / #! / dışında dizini sorgu dizesine yeniden yaz )

... ve dizin sayfanız / site giriş noktanız için önbellek bozmaya ihtiyacınız varsa , yenilemek için her zaman JavaSript kullanabilirsiniz .


2
<script type="text/javascript">
// front end cache bust

var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];   
for (i=0; i < cacheBust.length; i++){
     var el = document.createElement('script');
     el.src = cacheBust[i]+"?v=" + Math.random();
     document.getElementsByTagName('head')[0].appendChild(el);
}
</script> 

Yeni sürümlerin geliştirilmesi / test edilmesi sırasında önbellek bir sorun olabilir çünkü tarayıcı, sunucu ve hatta bazen 3G telco (mobil dağıtım yapıyorsanız) statik içeriği (örneğin JS, CSS, HTML, img) önbelleğe alır. URL'ye sürüm numarası, rastgele sayı veya zaman damgası ekleyerek bunun üstesinden gelebilirsiniz, örneğin: JSP: <script src = "js / excel.js? Time = <% = new java.util.Date ()%>"> </ script> Saf HTML çalıştırıyorsanız (JSP, ASP, PHP sunucu sayfaları yerine) sunucu size yardımcı olmayacaktır. Tarayıcıda, bağlantılar JS çalışmadan önce yüklenir, bu nedenle bağlantıları kaldırmanız ve JS ile yüklemeniz gerekir
Conete Cristian

Bunun JS dosyalarını eşzamanlı olarak sırayla yükleyeceğini sanmıyorum.
Stealth Rabbi

0
 <script>
    var storedSrcElements = [
         "js/exampleFile.js",
         "js/sampleFile.js",
         "css/style.css"
          ];

    var head= document.getElementsByTagName('head')[0];
    var script;
    var link;
    var versionNumberNew = 4.6;

    for(i=0;i<storedSrcElements.length;i++){
     script= document.createElement('script');
     script.type= 'text/javascript';
     script.src= storedSrcElements[i] + "?" + versionNumberNew;
     head.appendChild(script);
    }     


     </script> 


       ### Change the version number  (versionNumberNew) when you want the new files to be loaded  ###

0

Umarım bu, harici JS dosyasını enjekte etmenize yardımcı olur

<script type="text/javascript"> 
var cachebuster = Math.round(new Date().getTime() / 1000); 
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>

Kaynak - JavaScript'te önbellek engelleme kodu

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.