Saya telah memperhatikan bahwa beberapa browser (khususnya, Firefox dan Opera) yang sangat bersemangat dalam menggunakan cache salinan .css dan .js file, bahkan antara sesi browser. Hal ini menyebabkan masalah ketika anda memperbarui satu file tersebut tetapi pengguna's browser terus menggunakan salinan cache.
Pertanyaannya adalah: apa adalah cara yang paling elegan memaksa pengguna's browser untuk reload file yang ketika itu telah berubah?
Idealnya, solusi tidak akan memaksa browser untuk reload file pada setiap kunjungan ke halaman. Saya akan posting saya sendiri solusi sebagai jawaban, tapi saya ingin tahu jika ada yang memiliki solusi yang lebih baik dan saya'll biarkan suara anda memutuskan.
Update :
Setelah membiarkan diskusi di sini untuk sementara waktu, saya telah menemukan John Millikin dan da5id's saran untuk menjadi berguna. Ternyata ada istilah untuk ini: auto-versi.
Saya telah diposting baru jawaban di bawah ini yang merupakan kombinasi dari saya solusi asli dan John's saran.
Ide lain yang disarankan oleh SCdF akan untuk menambahkan palsu query string ke file. (Beberapa kode Python untuk secara otomatis menggunakan timestamp sebagai palsu query string tersebut disampaikan oleh pi.). Namun, ada beberapa diskusi tentang apakah atau tidak browser akan men-cache file dengan query string. (Ingat, kita ingin browser menyimpan cache file dan menggunakannya di masa depan kunjungan. Kami hanya ingin untuk mengambil file lagi ketika itu telah berubah.)
Karena tidak jelas apa yang terjadi dengan palsu query string, saya tidak menerima jawaban itu.
Update: ditulis Ulang untuk memasukkan saran-saran dari John Millikin dan da5id. Solusi ini ditulis di PHP, tapi harus dengan mudah diadaptasi untuk bahasa lain.
Update 2: Menggabungkan komentar dari Nick Johnson yang asli .htaccess
regex dapat menyebabkan masalah dengan file seperti json-1.3.js
. Solusinya adalah dengan hanya menulis ulang jika ada persis 10 digit di akhir. (Karena 10 digit mencakup semua cap dari 9/9/2001 untuk 11/20/2286.)
Pertama, kami gunakan aturan penulisan ulang berikut di .htaccess:
RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]
Sekarang, kita menulis kode PHP berikut fungsi:
/**
* 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);
}
Sekarang, di manapun anda termasuk CSS anda, mengubahnya dari ini:
<link rel="stylesheet" href="/css/base.css" type="text/css" />
Untuk ini:
<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />
Dengan cara ini, anda tidak perlu memodifikasi tag link lagi, dan pengguna akan selalu melihat CSS terbaru. Browser akan dapat men-cache file CSS, tapi ketika anda membuat perubahan ke file CSS browser akan melihat ini sebagai URL yang baru, sehingga tidak't menggunakan salinan cache.
Hal ini juga dapat bekerja dengan gambar, favicons, dan JavaScript. Pada dasarnya segala sesuatu yang tidak dihasilkan secara dinamis.
Sederhana Client-side Teknik
Secara umum, caching lebih baik.. Jadi ada beberapa teknik, tergantung pada apakah anda're memperbaiki masalah bagi diri anda sebagai anda mengembangkan sebuah situs web, atau apakah anda're berusaha untuk mengontrol cache dalam lingkungan produksi.
Umumnya pengunjung ke website anda memenangkan't memiliki pengalaman yang sama yang anda're memiliki ketika anda're mengembangkan situs. Karena rata-rata pengunjung datang ke situs ini kurang sering (mungkin hanya beberapa kali setiap bulan, kecuali anda're Google atau hi5 Jaringan), maka mereka cenderung untuk memiliki file dalam cache, dan itu mungkin cukup. Jika anda ingin force versi baru ke dalam browser, anda selalu dapat menambahkan query string untuk permintaan, dan benjolan nomor versi ketika anda membuat perubahan besar:
<script src="/myJavascript.js?version=4"></script>
Ini akan memastikan bahwa semua orang akan mendapatkan file baru. Ia bekerja karena browser terlihat di URL dari file untuk menentukan apakah ia memiliki salinan dalam cache. Jika server anda isn't dibentuk untuk melakukan apa-apa dengan query string, maka akan diabaikan, tetapi nama itu akan terlihat seperti sebuah file baru ke browser.
Di sisi lain, jika anda're mengembangkan sebuah situs web, anda don't ingin mengubah nomor versi setiap kali anda menyimpan perubahan ke versi pengembangan. Itu akan menjadi membosankan.
Jadi, sementara anda're mengembangkan situs anda, trik yang baik akan secara otomatis menghasilkan query parameter string:
<!-- Development version: -->
<script>document.write('<script src="/myJavascript.js?dev=' + Math.floor(Math.random() * 100) + '"\><\/script>');</script>
Menambahkan query string untuk permintaan adalah cara yang baik untuk versi sumber daya, tetapi untuk sebuah website sederhana ini mungkin tidak perlu. Dan ingat, caching adalah hal yang baik.
It's juga diperhatikan bahwa browser isn't selalu pelit tentang menjaga file dalam cache. Browser memiliki kebijakan untuk hal semacam ini, dan mereka biasanya bermain dengan aturan yang ditetapkan dalam spesifikasi HTTP. Ketika browser membuat permintaan ke server, bagian dari respon yang BERAKHIR header.. tanggal yang memberitahu browser berapa lama harus disimpan di cache. Waktu berikutnya browser datang di sebuah permintaan untuk file yang sama, ia melihat bahwa ia memiliki salinan dalam cache dan terlihat BERAKHIR tanggal untuk memutuskan apakah itu harus digunakan.
Jadi percaya atau tidak, itu's benar-benar server yang membuat browser cache begitu gigih. Anda bisa menyesuaikan pengaturan server anda dan mengubah EXPIRES header, tapi sedikit teknik I've tertulis di atas mungkin adalah cara yang lebih sederhana bagi anda untuk pergi tentang itu. Sejak caching yang baik, anda biasanya ingin mengatur tanggal jauh ke depan ("Jauh-masa Expires Header"), dan menggunakan teknik yang dijelaskan di atas untuk memaksa perubahan.
Jika anda're tertarik pada info lebih lanjut di HTTP atau bagaimana permintaan ini dibuat, buku yang bagus adalah "Kinerja Tinggi Situs Web" oleh Steve Souders. It's sebuah pengenalan yang sangat baik untuk subjek.
Google's mod_pagespeed plugin untuk apache akan melakukan auto-versi untuk anda. It's benar-benar licin.
Itu mem-parsing HTML di jalan keluar dari webserver (bekerja dengan PHP, rails, python, statis HTML-apa) dan penulisan ulang link untuk CSS, JS, file gambar sehingga mereka menyertakan kode id. Hal ini menyajikan file-file yang di modifikasi Url dengan sangat lama cache control pada mereka. Ketika file-file yang berubah, maka secara otomatis perubahan Url sehingga browser harus kembali menjemput mereka. Hal ini pada dasarnya hanya bekerja, tanpa ada perubahan pada kode anda. It'll bahkan mengecilkan kode anda di jalan keluar juga.
Bukan mengubah versi manual, saya akan merekomendasikan anda menggunakan MD5 hash sebenarnya file CSS.
Jadi URL anda akan menjadi sesuatu seperti
http://mysite.com/css/[md5_hash_here]/style.css
Anda masih bisa menggunakan aturan penulisan ulang untuk jalur keluar hash, tapi keuntungan adalah bahwa sekarang anda dapat menetapkan kebijakan cache untuk "cache selamanya", karena jika URL adalah sama, yang berarti bahwa file tersebut tidak berubah.
Anda kemudian dapat menulis skrip shell sederhana yang akan menghitung hash dari file dan update tag (anda'd mungkin ingin memindahkannya ke file terpisah untuk dimasukkan).
Cukup menjalankan script yang setiap kali perubahan CSS dan anda're baik. Browser HANYA akan reload file anda ketika mereka berubah. Jika anda membuat mengedit dan kemudian membatalkan itu, ada's tidak ada rasa sakit dalam mencari tahu versi mana yang anda butuhkan untuk kembali ke dalam rangka untuk pengunjung anda untuk tidak re-download.
Tidak yakin mengapa kalian mengambil begitu banyak rasa sakit untuk menerapkan solusi ini.
Semua yang perlu anda lakukan jika mendapatkan file's dimodifikasi timestamp dan menambahkan sebagai querystring untuk file
Di PHP saya akan melakukannya sebagai:
<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">
filemtime adalah fungsi PHP yang mengembalikan file yang dimodifikasi timestamp.
Anda hanya dapat menempatkan ?foo=1234
di akhir css / js impor, mengubah 1234 untuk menjadi apa pun yang anda suka. Lihatlah JADI sumber html untuk contoh.
Gagasannya adalah bahwa ? parameter yang dibuang / diabaikan pada permintaan tetap dan anda dapat mengubah jumlah itu ketika anda roll keluar versi baru.
Catatan: Ada beberapa argumen berkenaan dengan persis bagaimana hal ini mempengaruhi caching. Saya percaya secara umum inti dari itu adalah bahwa MENDAPATKAN permintaan, dengan atau tanpa parameter harus menjadi cachable, jadi solusi di atas harus bekerja.
Namun, ini adalah untuk kedua web server untuk memutuskan jika ingin mematuhi bagian dari spec dan browser pengguna menggunakan, karena dapat hanya pergi ke depan dan meminta versi baru pula.
I've mendengar ini disebut "auto versi". Metode yang paling umum adalah untuk menyertakan file statis's mtime di suatu tempat di URL, dan jalur keluar menggunakan rewrite penangan atau URL confs:
Lihat juga:
30 atau lebih ada jawaban yang besar saran untuk circa 2008 web. Namun, ketika datang ke modern, halaman aplikasi (LENGKAP), mungkin sudah saatnya untuk berpikir ulang beberapa asumsi mendasar... khusus gagasan bahwa itu diinginkan untuk web server untuk melayani hanya satu, versi terbaru dari file.
Bayangkan anda're pengguna yang memiliki versi M SPA dimuat ke browser anda:
/beberapa.template
/beberapa.template
— apakah anda ingin kembali versi M atau N template?Jika format /beberapa.template
berubah antara versi M dan N (atau file yang diubah namanya atau apa pun) anda mungkin don't ingin versi N template yang dikirim ke browser yang's menjalankan versi lama M parser.†
Aplikasi Web mengalami masalah ini ketika dua kondisi terpenuhi:
Setelah aplikasi anda perlu untuk melayani sampai beberapa versi di paralel, memecahkan caching dan "reload" menjadi sepele:
/v<release_tag_1>/...file...
, /v<release_tag_2>/...file...
<script>
dan <link>
tag, dll. untuk point ke berkas itu di salah satu berversi dirsLangkah terakhir terdengar rumit, karena bisa memerlukan memanggil pembuat URL untuk setiap URL di sisi server atau client-side code. Atau anda hanya bisa membuat pandai menggunakan <dasar>
tag dan mengubah versi saat ini dalam satu tempat.
† Salah satu cara sekitar ini adalah untuk menjadi agresif tentang memaksa browser untuk reload segalanya ketika versi baru dirilis. Tapi demi membiarkan apapun dalam proses operasi selesai, mungkin masih menjadi termudah untuk mendukung setidaknya dua versi dalam paralel: v-saat ini dan v-sebelumnya.
Jangan menggunakan foo.css?version=1! Browser aren't seharusnya cache Url dengan MENDAPATKAN variabel. Menurut http://www.thinkvitamin.com/features/webapps/serving-javascript-fast meskipun IE dan Firefox mengabaikan hal ini, Opera dan Safari don't! Sebaliknya, gunakan foo.v1234.css, dan menggunakan menulis ulang aturan untuk menghapus nomor versi.
Yang RewriteRule membutuhkan update kecil untuk js atau css file yang berisi notasi titik versioning di akhir. E. g. json-1.3.js.
Saya menambahkan dot negasi kelas [^.] untuk regex jadi .nomor. diabaikan.
RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
Untuk ASP.NET 4.5 dan lebih besar anda dapat menggunakan naskah bundling.
permintaan
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
ini untuk bundel AllMyScripts dan berisi query string pair v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2n1pkvb81. Query string v memiliki nilai token yang adalah pengenal unik yang digunakan untuk caching. Selama bundel doesn't berubah, ASP.NET aplikasi akan meminta AllMyScripts bundel menggunakan token ini. Jika ada file yang di bundle perubahan, ASP.NET optimasi kerangka akan menghasilkan token baru, menjamin bahwa browser permintaan untuk bundel akan mendapatkan terbaru bundel.
Ada manfaat lain untuk bundling termasuk peningkatan kinerja pada saat pertama kali halaman beban dengan minification.
Di sini adalah murni JavaScript solusi
(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);
}
})();
Di atas akan terlihat untuk terakhir kali pengguna mengunjungi situs anda. Jika kunjungan terakhir sebelum kau dirilis kode baru, menggunakan lokasi.reload(benar)
untuk memaksa refresh halaman dari server.
Saya biasanya memiliki ini sebagai yang pertama script dalam <head>
sehingga's dievaluasi sebelum setiap konten lainnya beban. Jika reload perlu terjadi, it's hampir tidak terlihat bagi pengguna.
Saya menggunakan penyimpanan lokal untuk menyimpan kunjungan terakhir timestamp pada browser, tapi anda dapat menambahkan cookie ke dalam campuran jika anda'kembali mencari untuk mendukung versi IE.
Di Laravel (PHP) yang bisa kita lakukan dalam berikut dengan jelas dan dengan cara yang elegan (menggunakan file modifikasi timestamp):
<script src="{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>
Dan serupa untuk CSS
<link rel="stylesheet" href="{{asset('css/your.css?v='.filemtime('css/your.css'))}}">
Posting menarik. Setelah membaca semua jawaban di sini dikombinasikan dengan fakta bahwa saya tidak pernah punya masalah dengan "palsu" query string (yang saya tidak yakin mengapa semua orang jadi enggan untuk menggunakan ini) saya kira solusi (yang menghilangkan kebutuhan untuk apache rewrite rules seperti pada jawaban yang diterima) adalah untuk menghitung pendek HASH dari file CSS isi (bukan file datetime) sebagai palsu querystring.
Hal ini akan mengakibatkan hal-hal berikut:
<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />
Tentu saja datetime solusi juga mendapatkan pekerjaan yang dilakukan dalam hal mengedit file CSS, tapi saya pikir itu adalah tentang css isi file dan file datetime, jadi mengapa mendapatkan ini bercampur?
Untuk perkembangan saya, saya menemukan bahwa chrome memiliki solusi yang bagus.
https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload
Dengan alat pengembang terbuka, hanya panjang klik tombol refresh dan membiarkan pergi setelah anda membawa lebih dari "Mengosongkan Cache dan Keras Reload".
Ini adalah teman terbaik saya, dan super ringan cara untuk mendapatkan apa yang anda inginkan!
Terima kasih di Kip untuk solusi sempurna!
Saya diperpanjang untuk menggunakannya sebagai Zend_view_Helper. Karena klien saya menjalankan halaman di virtual host saya juga diperpanjang untuk itu.
Berharap itu membantu orang lain juga.
/**
* Extend filepath with timestamp to force browser to
* automatically refresh them if they are updated
*
* This is based on Kip's version, but now
* also works on virtual hosts
* @link http://stackoverflow.com/questions/118884/what-is-an-elegant-way-to-force-browsers-to-reload-cached-css-js-files
*
* Usage:
* - extend your .htaccess file with
* # Route for My_View_Helper_AutoRefreshRewriter
* # which extends files with there timestamp so if these
* # are updated a automatic refresh should occur
* # RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
* - then use it in your view script like
* $this->headLink()->appendStylesheet( $this->autoRefreshRewriter($this->cssPath . 'default.css'));
*
*/
class My_View_Helper_AutoRefreshRewriter extends Zend_View_Helper_Abstract {
public function autoRefreshRewriter($filePath) {
if (strpos($filePath, '/') !== 0) {
// path has no leading '/'
return $filePath;
} elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . $filePath)) {
// file exists under normal path
// so build path based on this
$mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $filePath);
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
} else {
// fetch directory of index.php file (file from all others are included)
// and get only the directory
$indexFilePath = dirname(current(get_included_files()));
// check if file exist relativ to index file
if (file_exists($indexFilePath . $filePath)) {
// get timestamp based on this relativ path
$mtime = filemtime($indexFilePath . $filePath);
// write generated timestamp to path
// but use old path not the relativ one
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
} else {
return $filePath;
}
}
}
}
Sorak-sorai dan terima kasih.
Belum menemukan klien sisi DOM pendekatan membuat script node (atau css) elemen dinamis:
<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>
google chrome memiliki Keras Reload serta Kosongkan Cache dan Keras Reload pilihan.Anda dapat klik dan tahan tombol reload (Dalam Memeriksa Mode) untuk memilih salah satu .
Anda dapat memaksa "sesi caching" jika anda menambahkan sesi-id sebagai spureous parameter js/css file:
<link rel="stylesheet" src="myStyles.css?ABCDEF12345sessionID" />
<script language="javascript" src="myCode.js?ABCDEF12345sessionID"></script>
Jika anda ingin versi-lebar caching anda bisa menambahkan beberapa kode untuk mencetak file upload atau serupa. Jika anda're menggunakan Java, anda dapat menggunakan kustom-tag untuk membuat link dengan cara yang elegan.
<link rel="stylesheet" src="myStyles.css?20080922_1020" />
<script language="javascript" src="myCode.js?20080922_1120"></script>
Katakanlah anda memiliki sebuah file yang tersedia di:
/styles/screen.css
anda juga dapat menambahkan sebuah parameter kueri dengan informasi versi ke URI, misalnya:
/styles/screen.css?v=1234
atau anda dapat menambahkan informasi versi, misalnya:
/v/1234/styles/screen.css
IMHO kedua metode yang lebih baik untuk file CSS karena mereka dapat merujuk ke gambar menggunakan Url relatif, yang berarti bahwa jika anda menetapkan background-image
seperti:
body {
background-image: url('images/happy.gif');
}
URL-nya secara efektif akan:
/v/1234/styles/images/happy.gif
Ini berarti bahwa jika anda memperbarui versi nomor yang digunakan server akan memperlakukan ini sebagai sumber daya baru dan tidak menggunakan versi cache. Jika anda tempat anda nomor versi pada Subversion/CVS/dll. revisi ini berarti bahwa perubahan gambar yang direferensikan dalam file CSS akan diperhatikan. Yang isn't dijamin dengan skema pertama, yaitu URL images/happy.gif
relatif /gaya/layar.css?v=1235
adalah /styles/images/happy.gif
yang doesn't berisi informasi versi.
Saya telah menerapkan solusi caching menggunakan teknik ini dengan Java servlets dan hanya menangani permintaan /v/*
dengan servlet bahwa delegasi untuk sumber daya yang mendasari (yaitu /gaya/layar.css
). Dalam perkembangan mode I set cache header yang memberitahu klien untuk selalu memeriksa kesegaran dari sumber daya server (ini biasanya hasil 304 jika anda mendelegasikan ke Tomcat's DefaultServlet
dan .css
, .js
, dll. file tidak't berubah) sedangkan pada penyebaran mode I set header yang mengatakan "cache selamanya".