ブラウザーにキャッシュされたCSS / JSファイルを強制的に再読み込みさせる方法は?


993

一部のブラウザー(特に、FirefoxとOpera)は、ブラウザーセッション間であっても、.cssファイルと.jsファイルのキャッシュされたコピーを非常に熱心に使用していることに気付きました。これにより、これらのファイルの1つを更新しても問題が発生しますが、ユーザーのブラウザーはキャッシュされたコピーを使い続けます。

問題は、ファイルが変更されたときにユーザーのブラウザーにファイルの再読み込みを強制する最もエレガントな方法は何ですか?

理想的には、ソリューションは、ページにアクセスするたびにブラウザにファイルをリロードさせません。私は自分の解決策を回答として投稿しますが、誰かがより良い解決策を持っているかどうか知りたいので、投票を決定させてください。

更新:

しばらくここでの議論を許可した後、私はJohn Millikinda5idの提案が役立つことがわかりました。これには「自動バージョン管理」という用語があることがわかりました

私の元の解決策とジョンの提案を組み合わせた新しい回答を以下に投稿しました。

SCdFによって提案された別のアイデアは、偽のクエリ文字列をファイルに追加することです。(偽のクエリ文字列がpiによって送信されたときにタイムスタンプを自動的に使用する一部のPythonコード)。ただし、ブラウザがクエリ文字列を含むファイルをキャッシュするかどうかについては、いくつかの議論があります。(ブラウザにファイルをキャッシュして、次回のアクセス時に使用することを忘れないでください。ファイルが変更された場合にのみ、再度ファイルをフェッチする必要があります。)

偽のクエリ文字列で何が起こるかは明らかではないので、私はその答えを受け入れません。


私はこれを.htaccessに入れており、キャッシュされたファイルに関する問題はありません:ExpiresActive On ExpiresDefault "modification"
フランクConijn 2014年

2
ファイルのURLにバージョン情報を追加することが最善の方法であることは間違いありません。いつでも、誰にとっても機能します。しかし、それを使用しておらず、CSSまたはJSファイルを独自のブラウザーで時々再ロードする必要がある場合は、それを独自のタブで開いてSHIFT-reload(またはCTRL-F5)を押すだけです!(非表示の)iframeにファイルをロードし、ロードされるまで待機してからを呼び出すことにより、JSを使用して同じことを効果的に行うことができますiframe.contentWindow.location.reload(true)stackoverflow.com/a/22429796/999120のメソッド(4)を参照してください。これは画像に関するものですが、同じことが当てはまります。
Doin

2
この質問の仕方とそれ以降更新された方法に本当に感謝しています。それは私が答えに期待すべきことを完全に説明しました。これからの質問では、このアプローチに従います。乾杯!
rd22

回答:


455

更新:John Millikinda5id からの提案を組み込むように書き直されました。このソリューションはPHPで記述されていますが、他の言語に簡単に適合させることができます。

更新2:ニックジョンソンからのコメントを組み込んで、元の.htaccess正規表現がなどのファイルで問題を引き起こす可能性があることを示しますjson-1.3.js。解決策は、末尾に正確に10桁がある場合にのみ書き換えることです。(10桁は2001年9月9日から2286年11月20日までのすべてのタイムスタンプをカバーするため。)

まず、.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);
}

ここで、CSSを含める場所はどこでも、次のように変更します。

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

これに:

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

これにより、リンクタグを再度変更する必要がなくなり、ユーザーには常に最新のCSSが表示されます。ブラウザーはCSSファイルをキャッシュできますが、CSSに変更を加えると、ブラウザーはこれを新しいURLとして認識するため、キャッシュされたコピーを使用しません。

これは、画像、ファビコン、JavaScriptでも機能します。基本的に、動的に生成されないものは何でも。


16
ファイル名の変更(base.1221534296.css)ではなく、バージョン管理用のパラメーター(base.css?v = 1221534296)を使用することを除いて、自分の静的コンテンツサーバーはまったく同じです。しかし、あなたのやり方はもう少し効率的かもしれないと思います。とてもかっこいい。
Jens Roland、2011年

4
@Kip:非常に洗練されたソリューション。URLの書き換えには、URLを単純化するだけでなく、提供する機能がはるかに多いことは明らかです。
James P.

37
私はこれに問題があり、ファイルシステムに何度もアクセスする-正確に-リンク数*リクエスト数/秒...それはあなたにとって問題かもしれないし、そうでないかもしれません。
トマーシュFejfar

3
@AlixAxel:いいえ、ブラウザはパラメータが変更されるとそれを再フェッチしますが、一部のパブリックプロキシはurlパラメータを含むファイルをキャッシュしないため、バージョンをパスに含めることをお勧めします。そして、mod_rewriteのオーバーヘッドは、WPOの他のすべてのパフォーマンスボトルネックと比較してごくわずかです
Jens Roland

8
最初のfile_existsチェックは本当に必要ですか?filemtime失敗するとfalseを返すので、filemtime値を変数に割り当てて、ファイルの名前を変更する前にfalseかどうかを確認しませんか?これにより、実際に加算される不要なファイル操作が1つ減ります。
Gavin

184

シンプルなクライアント側テクニック

一般的に、キャッシングは優れています。したがって、Webサイトの開発時に自分で問題を修正するかどうか、または本番環境でキャッシュを制御するかどうかによって、いくつかのテクニックがあります。

あなたのウェブサイトへの一般的な訪問者は、あなたがサイトを開発しているときと同じ経験をすることはありません。平均的な訪問者がサイトにアクセスする頻度が低いため(Googleまたはhi5 Networksでない限り、月に数回程度)、キャッシュにファイルが存在する可能性は低く、それで十分な場合があります。ブラウザに新しいバージョンを強制したい場合は、いつでもクエリ文字列をリクエストに追加し、大きな変更を加えるときにバージョン番号を上げることができます。

<script src="/myJavascript.js?version=4"></script>

これにより、全員が新しいファイルを確実に取得できるようになります。これは、ブラウザがファイルのURLを調べて、コピーがキャッシュにあるかどうかを判断するために機能します。サーバーがクエリ文字列で何かを実行するように設定されていない場合、それは無視されますが、名前はブラウザにとって新しいファイルのように見えます。

一方、Webサイトを開発している場合、開発バージョンの変更を保存するたびにバージョン番号を変更する必要はありません。それは退屈です。

したがって、サイトを開発している間は、クエリ文字列パラメーターを自動的に生成することをお勧めします。

<!-- Development version: -->
<script>document.write('<script src="/myJavascript.js?dev=' + Math.floor(Math.random() * 100) + '"\><\/script>');</script>

リクエストにクエリ文字列を追加することは、リソースをバージョン管理するための良い方法ですが、単純なWebサイトの場合、これは不要な場合があります。覚えておいてください、キャッシングは良いことです。

また、ブラウザがファイルをキャッシュに保持することについて必ずしもけちではないことにも注意する必要があります。ブラウザーにはこの種のポリシーがあり、通常、HTTP仕様に規定されているルールに従っています。ブラウザがサーバーにリクエストを送信するとき、レスポンスの一部はEXPIRESヘッダーです。キャッシュに保持する期間をブラウザに通知する日付です。次にブラウザーが同じファイルの要求に遭遇すると、キャッシュにコピーがあることがわかり、EXPIRES日付を調べて、それを使用するかどうかを決定します。

信じられないかもしれませんが、ブラウザのキャッシュを永続化しているのは実際にはサーバーです。サーバー設定を調整してEXPIRESヘッダーを変更することもできますが、上で書いた小さなテクニックは、おそらくそれを回避するためのはるかに簡単な方法です。キャッシングは適切であるため、通常はその日付をはるか先に設定し(「Far-future Expiresヘッダー」)、上記の手法を使用して変更を強制します。

HTTPの詳細やこれらのリクエストの作成方法に興味がある場合は、Steve Soudersによる「High Performance Web Sites」が良い本です。それは主題への非常によい導入です。


3
Javascriptを使用してクエリ文字列を生成するクイックトリックは、活発な開発中にうまく機能します。PHPでも同じことを行いました。
アランチューリング

2
これは、元のポスターの望ましい結果を達成する最も簡単な方法です。ページをロードするたびに.cssファイルまたは.jsファイルを強制的に再ロードする場合は、mod_rewriteメソッドが適切に機能します。この方法でも、実際にファイルを変更して本当に強制的に再ロードさせるまでは、キャッシュが可能です。
scott80109 2014

@keparo、私がすべてのページにjqueryの十分な数があるので、これを手動で変更する場合、1か月かかります。各ページにコーディングすることなく、私がすべて解決するのを助けることができるなら。
クラッカー

1
私が使用している場合これが私のCSSのために動作していないよう:<link href='myCss.css?dev=14141'...>
ヌーメノン

3
これは実行可能なソリューションではありません。かなりの数のブラウザは、クエリ文字列が含まれているもののキャッシュを拒否します。これが、静的コンテンツへの参照にクエリ文字列がある場合、Google、GTMetrix、および類似のツールがフラグを立てる理由です。それは確かに開発のためのまともなソリューションですが、生産のためのソリューションではありません。また、ブラウザはサーバーではなくキャッシュを制御します。サーバーは、更新する必要がある場合にのみ推奨します。ブラウザはサーバーをリッスンする必要がありません(多くの場合はリッスンしません)。モバイルデバイスは、この典型的な例です。
Nate I

113

Googleのmod_pagespeed apache用プラグインは、自動バージョン管理を行います。それは本当に滑らかです。

Webサーバーから出る途中でHTMLを解析し(PHP、rails、python、静的HTMLなどすべてで機能)、CSS、JS、画像ファイルへのリンクを書き換えて、IDコードを含めます。非常に長いキャッシュ制御を使用して、変更されたURLでファイルを提供します。ファイルが変更されると、自動的にURLが変更されるため、ブラウザーはそれらを再フェッチする必要があります。コードに変更を加えなくても、基本的には機能します。途中でコードを縮小することもできます。


1
すばらしいですが、まだベータ版です。エンタープライズサービスに使用できますか?
イ・サンヒョン2011

26
明らかにブラウザの問題である場合、これは間違っています(ソースを自動操作します)。私たち(開発者)に本当のブレインワイプリフレッシュを提供:<ctrl> + F5
T4NK3R

25
mod_pagespeedは、機能的には、html / css / jsの完全に自動化されたビルド/コンパイル手順と同等です。ビルドシステムが本質的に間違っている、または完全に自動化されていることに何か問題があると考える深刻な開発者を見つけるのは難しいでしょう。クリーンビルドの例えは、mod_pagespeedのキャッシュをクリアすることです:code.google.com/p/modpagespeed/wiki/…
Leopd 2011

3
@ T4NK3R mod_pagespeedは、キャッシュ管理を行うためにソースで何もする必要はありません。それは、縮小化などに役立つことができると簡単に述べられています。それが「間違っている」かどうかに関して、それは完全に主観的です。それはあなたにとっては間違っているかもしれませんが、それが本質的に悪いということではありません。
Madbreaks、2012

2
それはあなたがソースからビルドする必要があまりにもかかわらず、nginxのと連携して動作します。developers.google.com/speed/pagespeed/module/...
のRohit

93

バージョンを手動で変更する代わりに、実際のCSSファイルのMD5ハッシュを使用することをお勧めします。

だからあなたのURLは次のようになります

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

リライトルールを使用してハッシュを取り除くこともできますが、URLが同じであればファイルが変更されないことを意味するため、キャッシュポリシーを「永久にキャッシュ」に設定できるという利点があります。

次に、ファイルのハッシュを計算してタグを更新する単純なシェルスクリプトを記述できます(おそらく、それを別のファイルに移動して含める必要があります)。

CSSが変更されるたびにそのスクリプトを実行するだけで問題ありません。ブラウザは、ファイルが変更されたときにのみファイルをリロードします。編集を行って元に戻した場合、訪問者が再ダウンロードしないようにするために、どのバージョンに戻る必要があるかを判断するのに苦労はありません。


1
残念ながら、実装方法がわかりません。アドバイスをお願いします...詳細...
マイケル・フェルプス

シェルやルビーなどでの実装は素晴らしいでしょう
Peter

3
非常に素晴らしい解決策ですが、1回のページアクセスごとに、すべてのファイルリクエスト(css、js、images、html..etc)でファイルのハッシュを計算するのはリソースを消費していると思います。
DeepBlue

これは、gulp、grunt、またはwebpackでjsまたはcssバンドルを使用するユーザー向けの標準的なソリューションです。ソリューションごとに実装は異なりますが、ビルドステップとしてファイルをハッシュすることは一般的であり、最新のバンドルアプリで推奨されます
BrandonSørenCulley

@DeepBlue- 「CSSが変更されるたびにそのスクリプトを実行する」と回答。それはすべてのページ訪問にあるわけではありません。OTOH答えは主要な詳細を省きます-変更されたハッシュはどのようにURLの一部になりますか?わからない...
ToolmakerSteve

70

なぜ皆さんがこのソリューションを実装するのにそれほど苦労しているのかわかりません。

ファイルの変更されたタイムスタンプを取得し、クエリ文字列としてファイルに追加する場合に必要なことすべて

PHPでは、次のようにします。

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

filemtimeは、ファイルの変更されたタイムスタンプを返すPHP関数です。


そのまま使えますmycss.css?1234567890
Gavin

3
非常にエレガントですが、<link rel="stylesheet" href="mycss.css?<?php echo filemtime('mycss.css') ?>"/>GET変数を使用してURLをキャッシュすることに関するこのスレッドの引数の一部(推奨フォーマット)が正しい場合に備えて、少し変更しましたが、
luke_mclachlan

私の最後のコメントに加えて、私はワードプレスが使用して?ver=いるのを見たので、誰が知っているのでしょう!
luke_mclachlan

素晴らしいソリューション。さらに、完全修飾ドメイン名(FQDN)ではfilemtimeが機能しないことがわかったので、href部分にはFQDNを使用し、filemtime部分には$ _SERVER ["DOCUMENT_ROOT"]を使用しました。例:<link rel = "stylesheet" href = "http://theurl/mycss.css?v = <?php echo filemtime($ _ SERVER [" DOCUMENT_ROOT "]。 '/mycss.css')?>" />
rrtx2000

まことにありがとうございます。シンプルで良い。これはPythonの場合です:progpath = os.path.dirname(sys.argv [0])def versionize(file):timestamp = os.path.getmtime( '%s /../ web /%s'%(progpath 、ファイル))戻り '%s?v =%s'%(ファイル、タイムスタンプ)print <link href = "%s" rel = "stylesheet" '' type = "text / css" /> '\%versionize( 'css / main.css')
dlink

52

?foo=1234css / jsインポートの最後に置くだけで、1234を好きなように変更できます。例としてSO htmlソースを見てください。

ということはあるのでしょうか?いずれにしても、リクエストでパラメーターは破棄/無視され、新しいバージョンをロールアウトするときにその番号を変更できます。


注:これがキャッシュにどのように影響するかについては、いくつかの議論があります。私はそれの一般的な要点は、パラメーターの有無にかかわらずGETリクエストがキャッシュ可能でなければならないので、上記のソリューションが機能するはずであると信じています。

ただし、仕様のその部分に準拠するかどうかを決定するのはWebサーバーと、ユーザーが使用するブラウザーの両方です。これは、先に進んでとにかく新しいバージョンを要求できるためです。


ナンセンス。クエリ文字列(別名GETパラメータ)はURLの一部です。キャッシュでき、キャッシュされます。これは良い解決策です。
troelskn 2008

9
@troelskn:HTTP 1.1仕様は、(クエリパラメータを使用したGETリクエストとHEADリクエストに関して)別のことを述べています:サーバーは明示的な有効期限を提供しない限り、キャッシュはそのようなURIへの応答を新鮮なものとして扱わないでください。w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9
マイケルジョンソンを

4
すべての主要なブラウザでバージョン管理のクエリ文字列タイプを試してみましたが、それらはファイル、仕様、またはそうでないものをキャッシュします。ただし、プロキシソフトウェアをキャッシュしてもファイルがキャッシュされない可能性があるため、クエリ文字列を悪用せずにstyle.TIMESTAMP.css形式を使用することをお勧めします。
Tomas Andrle

34
なんらかの理由で、Stackoverflow自体がクエリ文字列メソッドを使用することに注目してください。
ジェイソン

2
?= parameterを使用しても、パラメータの変更時にブラウザがキャッシュファイルを再フェッチしないことを確認しました。唯一の方法は、Kipの回答に
応じ

41

これは「自動バージョン管理」と呼ばれています。最も一般的な方法は、静的ファイルのmtimeをURLのどこかに含め、書き換えハンドラまたはURL confを使用してそれを取り除くことです。

以下も参照してください。


3
おかげで、これは私の考えが議論された別のケースだったと思います。それが何と呼ばれていたかわからなかったので、Google検索で見つけられませんでした。
Kip

27

30ほどの既存の回答は、2008年頃のWebサイトにとって素晴らしいアドバイスです。ただし、最新のシングルページアプリケーション(SPA)に関しては、基本的な前提を再考するときが来ているかもしれません。具体的には、Webサーバーが単一の最新バージョンのみを提供することが望ましいという考えです。ファイル。

あなたがブラウザにSPAのバージョンMをロードしているユーザーを想像してください。

  1. CDパイプラインは、アプリケーションの新しいバージョンNをサーバーにデプロイします
  2. SPA内を移動し、XHRをサーバーに送信して取得します。 /some.template
    • (ブラウザがページを更新していないため、バージョンMを実行しています)
  3. サーバーは次の内容で応答します/some.template— テンプレートのバージョンMまたはNを返しますか?

/some.templateバージョンMNの間で形式が変更された場合(またはファイルの名前が変更された場合など)、古いバージョンMのパーサーを実行しているブラウザーにバージョンNのテンプレートを送信したくない場合があります。†

次の2つの条件が満たされた場合、Webアプリでこの問題が発生します。

  • 最初のページのロード後、リソースが非同期的に要求される
  • アプリのロジックは、リソースコンテンツについて(将来のバージョンで変更される可能性がある)ことを前提としています

アプリが複数のバージョンを同時に提供する必要がある場合、キャッシングと「リロード」を解決することは簡単です。

  1. すべてのサイトファイルをバージョン付きディレクトリにインストールします:/v<release_tag_1>/…files…/v<release_tag_2>/…files…
  2. ブラウザがファイルを永久にキャッシュできるようにHTTPヘッダーを設定する
    • (さらに良いことに、すべてをCDNに入れます)
  3. すべての更新<script><link>バージョン管理のdirsの一つに、そのファイルを指すようにタグなどを

サーバーサイドコードまたはクライアントサイドコードのすべてのURLに対してURLビルダーを呼び出す必要があるため、この最後のステップはトリッキーに聞こえます。または、<base>タグを巧みに使用して、現在のバージョンを1か所で変更することもできます。

†これを回避する1つの方法は、新しいバージョンがリリースされたときにブラウザーにすべてをリロードさせることについて積極的にすることです。ただし、進行中の操作を完了するために、v-currentとv-previousの少なくとも2つのバージョンを同時にサポートするのが最も簡単な場合があります。


マイケル-あなたのコメントは非常に関連があります。私はここで自分のSPAの解決策を見つけようとしています。私はいくつかの指針を得ましたが、自分で解決策を考え出さなければなりませんでした。結局、思いついたことに本当に満足していたので、ブログ投稿とこの質問への回答(コードを含む)を書きました。ポインタをありがとう
statler

素晴らしいコメント。キャッシュバスティングとHTTPキャッシングが、SPAの新しい問題をコメントせずにWebサイトのキャッシング問題の真の解決策として話している間、これは限界的なケースであるかのように理解できません。
David Casillas 2017年

1
優れたレスポンスと絶対に理想的な戦略!そして、baseタグを言及するためのボーナスポイント!古いコードのサポートに関しては、これは常に可能であるとは限らず、常に良い考えでもありません。コードの新しいバージョンは、アプリの他の部分に対する重大な変更をサポートしている場合や、緊急修正、脆弱性パッチなどが含まれている場合があります。私はこの戦略を自分で実装する必要がありますが、アーキテクチャ全体で古いバージョンにタグを付けobsolete、次回非同期呼び出しが行われたときにリロードを強制できるようにする必要があると常に感じていました(またはWebSocketを介してすべてのセッションを強制的に認証解除します) )。
Jonny Asmar 2017

シングルページアプリケーションに関してよく考えられた答えを見るのはうれしいです。
Nate I

詳細を検索する場合は、「青緑の展開」です。
フィル

15

foo.css?version = 1は使用しないでください。ブラウザは、GET変数を使用してURLをキャッシュすることは想定されていません。http://www.thinkvitamin.com/features/webapps/serving-javascript-fastによると、IEとFirefoxはこれを無視していますが、OperaとSafariはそうではありません!代わりに、foo.v1234.cssを使用し、書き換えルールを使用してバージョン番号を削除します。


1
まず第一に、ブラウザーはキャッシュしない、それはHTTPの機能です。なぜhttpがURIの構造を気にするのですか?クエリ文字列でアイテムをキャッシュしないように、HTTPキャッシュがURIのセマンティクスを理解する必要があることを示す仕様への公式の参照はありますか?
AnthonyWJones 2008

13
オブジェクトをキャッシュする機能を含むWebブラウザー(ブラウザーのキャッシュディレクトリを確認してください)。HTTPは、キャッシュ制御を提案するサーバーからクライアント(プロキシ、ブラウザ、スパイダーなど)へのディレクティブを含むプロトコルです。
tzot 2008

13

Laravel(PHP)では、次の明確でエレガントな方法(ファイル変更タイムスタンプを使用)で実行できます。

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

そしてCSSについても同様です

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

html出力の例(Unixタイムスタンプfilemtimeとして時間を返す)

<link rel="stylesheet" href="assets/css/your.css?v=1577772366">

このコマンドの出力はhtmlで何ですか??v = 3、?v = 4などのバージョンのみを更新する必要がある場合はどうしますか?-ユーザーがWebサイトにアクセスするたびにブラウザにCSSを強制的にロードしません
Gediminas

filemtime: "この関数は、ファイルのデータブロックが書き込まれた時刻、つまりファイルの内容が変更された時刻を返します。" src:php.net/manual/en/function.filemtime.php
KamilKiełczewski17年

11

RewriteRuleは、末尾にドット表記のバージョン管理を含むjsまたはcssファイルの小さな更新を必要とします。例:json-1.3.js。

ドット否定クラス[^。]を正規表現so .numberに追加しました。無視されます。

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

2
入力ありがとうございます!私はこの記事を書いて以来、私もこれに熱中しています。私の解決策は、ファイル名の最後の部分に正確に10桁が含まれている場合にのみ書き換えることでした。(10桁は9/9/2001から11/20/2286までのすべてのタイムスタンプをカバーします。)この正規表現を含めるように私の回答を更新しました:^(.*)\.[\d]{10}\.(css|js)$ $1.$2
Kip

正規表現は理解していますが、[^.]ここで解決している問題がわかりません。また、\d文字クラスの内部に書き込むことには利点はありません- \d+同じことを行います。投稿されたとおり、パターンは任意の数の文字(貪欲に)、次にリテラルドット、非ドット、1つ以上の数字、次にドット、cssまたはjs、次にファイル名の末尾に一致します。サンプル入力が一致しません:regex101.com/r/RPGC62/1
mickmackusa

10

ASP.NET 4.5以降では、スクリプトバンドルを使用できます。

リクエストhttp://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81はバンドルAllMyScriptsに対するものであり、クエリ文字列ペアv = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81が含まれています。クエリ文字列vには、キャッシュに使用される一意の識別子である値トークンがあります。バンドルが変更されない限り、ASP.NETアプリケーションはこのトークンを使用してAllMyScriptsバンドルを要求します。バンドル内のファイルが変更されると、ASP.NET最適化フレームワークが新しいトークンを生成し、バンドルに対するブラウザー要求が最新のバンドルを取得することを保証します。

バンドル化には他にも、縮小による初回のページ読み込み時のパフォーマンスの向上などの利点があります。


bundle.configでcssまたはjsファイルを変更するだけで変更を行わないようにしてください。キャッシュの問題を解決するにはどうすればよいですか?
vedankita kumbhar 2017

10

これが純粋なJavaScriptソリューションです

(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をサポートする場合は、Cookieをミックスに追加できます。


私はこのようなことを試しましたが、これはリロードされたページでのみ機能しますが、サイトに同じcss /画像を共有する複数のページがある場合、他のページは引き続き古いリソースを使用します。
DeepBlue

9

興味深い投稿。ここですべての回答を読んだことと、「偽の」クエリ文字列で問題が発生したことがないという事実(誰もがこれを使用するのをためらっている理由がわからない)を組み合わせることで、解決策を推測します(これにより、Apacheの書き換えルールが不要になります。受け入れられた回答のように)(ファイルの日時ではなく)CSSファイルの内容の短いハッシュを偽のクエリ文字列として計算することです。

これにより、次のようになります。

<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />

もちろん、日時ソリューションもCSSファイルの編集の場合に仕事を完了しますが、それはファイルの日時ではなくcssファイルの内容に関するものだと思うので、なぜこれらを混同するのですか?


8

私の開発では、Chromeが優れたソリューションであることがわかりました。

https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload

開発者ツールを開いた状態で、更新ボタンを長押しし、[キャッシュとハードリロードを空にする]にカーソルを合わせたら放します。

これは私の親友であり、あなたが欲しいものを手に入れる超軽量の方法です!


また、開発環境としてChromeを使用している場合、別の非侵襲的な解決策はキャッシュを無効にすることです。設定の歯車の下で、「キャッシュを無効にする」を選択してディスクキャッシュを無効にすることができます(注:DevToolsが表示/開く必要がありますこれが機能するために)。
Velojet 2016

7

Kipの完璧な解決策に感謝します!

Zend_view_Helperとして使用できるように拡張しました。私のクライアントは仮想ホストで自分のページを実行しているので、そのためにページも拡張しました。

それが他の誰かにも役立つことを願っています。

/**
 * 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;
            }
        }
    }

}

乾杯と感謝。


7

スクリプトノード(またはCSS)要素を動的に作成するクライアント側の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>

6

google chromeには、ハードリロードのほか、空のキャッシュとハードリロードのオプションがあります。リロードボタンをクリックして押したまま(検査モード)で選択できます。


「モードの点検」によって、明確にするために、彼らはF12別名「開発ツール」、I、別名+別名Ctrl + Shiftキーを参照しているant menu> More Tools> Developer Tools、別名right click> Inspect Element。すべてのリロードでハードリロードするために、開発ツール(場所を忘れた)のどこかに埋め込まれた設定もあります。
Jonny Asmar 2017

5

js / cssファイルの不正なパラメータとしてセッションIDを追加すると、「セッション全体のキャッシュ」を強制できます。

<link rel="stylesheet" src="myStyles.css?ABCDEF12345sessionID" />
<script language="javascript" src="myCode.js?ABCDEF12345sessionID"></script>

バージョン全体のキャッシュが必要な場合は、ファイルの日付などを出力するコードを追加できます。Javaを使用している場合は、カスタムタグを使用して、エレガントな方法でリンクを生成できます。

<link rel="stylesheet" src="myStyles.css?20080922_1020" />
<script language="javascript" src="myCode.js?20080922_1120"></script>

5

次の場所にあるファイルがあるとします。

/styles/screen.css

バージョン情報を含むクエリパラメータをURIに追加できます。例:

/styles/screen.css?v=1234

または、バージョン情報を付加できます。例:

/v/1234/styles/screen.css

私見2番目の方法は、相対URLを使用して画像を参照できるため、CSSファイルに適していますbackground-image

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

そのURLは事実上次のようになります。

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

つまり、使用するバージョン番号を更新すると、サーバーはこれを新しいリソースとして扱い、キャッシュされたバージョンを使用しません。バージョン番号をSubversion / CVS / etcに基づいている場合。これは、CSSファイルで参照されている画像への変更が通知されることを意味します。これは、最初のスキームでは保証されません。つまり、images/happy.gif相対URL /styles/screen.css?v=1235/styles/images/happy.gifバージョン情報が含まれていません。

私は、Javaサーブレットでこの手法を使用してキャッシングソリューションを実装/v/*し、基盤となるリソース(つまり/styles/screen.css)に委任するサーブレットでリクエストを単純に処理します。開発モードでは、私は(これは通常、あなたがTomcatのに委任する場合は304になり、常にサーバとリソースの鮮度を確認するために、クライアントに伝えるヘッダキャッシュ設定DefaultServlet.css.js展開モード中などのファイルが変更されていないが) 「永久にキャッシュ」というヘッダーを設定しました。


相対URLのみを使用する場合は、必要に応じて名前を変更できるフォルダを追加するだけで機能します。そして、ベースフォルダーから適切なフォルダーにリダイレクトすることを確認します(例:PHPの場合)<?php header( 'Location: folder1/login.phtml' ); ?>
グルーバー

1
2番目の方法を使用すると、CSSを変更すると、相対URLで参照されているすべての画像のキャッシュコピーが無効になります。
TomG、2013年

5

あなたは単にCSS / JSのURLでいくつかの乱数を追加することができます

example.css?randomNo=Math.random()

5

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

4

私は最近、これをPythonを使用して解決しました。ここにコード(他の言語に採用するのは簡単であるはずです):

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) 

このコードは基本的に、ファイルのタイムスタンプをクエリパラメータとしてURLに追加します。次の関数の呼び出し

script("/main.css")

結果になります

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

もちろん、HTMLを再度変更する必要がないという利点があります。CSSファイルに触れると、自動的にキャッシュの無効化がトリガーされます。非常にうまく機能し、オーバーヘッドは目立ちません。


os.stat()がボトルネックを作成する可能性はありますか?
hoju

@Richard統計は、ディスクが非常に遅く、リクエストが非常に多い場合にボトルネックになる可能性があります。その場合は、メモリ内のどこかにタイムスタンプをキャッシュし、新しい展開ごとにこのキャッシュを削除できます。しかし、この複雑さは、ほとんどのユースケースでは必要ありません。
pi。

4

git + PHPを使用している場合は、次のコードを使用して、gitリポジトリに変更があるたびにキャッシュからスクリプトをリロードできます。

exec('git rev-parse --verify HEAD 2> /dev/null', $gitLog);
echo '  <script src="/path/to/script.js"?v='.$gitLog[0].'></script>'.PHP_EOL;

4

キャッシュを避けたい開発者は、Chromeネットワークタブでキャッシュオプションを無効にできます。それ以外の場合は、2つのスクリプトタグを使用して、サーバーレンダリングフレームワークなしで実行できます。

<script type="text/javascript">
    document.write('<script type="text/javascript" src="myfile.js?q=' + Date.now() + '">
    // can't use myfile.js stuff yet
</script>')
<script type="text/javascript">
    // do something with myfile.js
</script>

4

この質問は非常に古く、誰かがこの問題をググるときに最初に現れます。これは、opが望む方法に対する質問への回答ではなく、開発およびテスト中にこの問題を抱えた開発者への回答です。また、重複としてマークされるため、このトピックについて新しい質問を投稿することはできません。

他の多くの人と同様に、私は簡単にキャッシュを削除したかっただけです。

"keep caching consistent with the file" ..その方法が面倒すぎる..

一般的に言って、私はもっとロードしても構わない-ほとんどのプロジェクトで変更されていないファイルを再度ロードすることさえ-実際には無関係です。アプリの開発中は、主にディスクから読み込んでいるlocalhost:port ため、このincrease in network traffic問題は問題を解決するものではありません

ほとんどの小規模なプロジェクトはただ遊んでいるだけで、最終的には生産されません。だから彼らのためにあなたはこれ以上何も必要としません。

そのため、Chrome Dev Toolsを使用している場合は、以下の画像のように、キャッシュを無効にするこのアプローチに従うことができます。 キャッシュされたファイルをChromeに強制的に再読み込みさせる方法

そして、Firefoxのキャッシュに関する問題がある場合: Firefoxでアセットを強制的に再読み込みする方法

開発中にFirefoxでキャッシュを無効にする方法 開発時にのみこれを行います。アプリを頻繁に更新し、回答に記載されているような専用のキャッシュ同期メカニズムを提供しない場合、ユーザーは古いキャッシュ無効化モジュールを使用するため、本番環境で強制的にリロードするメカニズムも必要です。上記。

はい、この情報は以前の回答にすでに含まれていますが、それを見つけるには引き続きGoogle検索を行う必要がありました。

うまくいけば、この答えは非常に明確であり、今あなたがする必要はありません。


OPが何かを尋ね、別の何かを答えました。これは、ローカルではなく、生産に力負荷についてではありません、あなたは無効キャッシュなどの上に従うことをエンドユーザーに求めることはできません
Jitendra Pancholi

3

ここでのすべての回答は、欠点があるネーミングスキームでのある種のバージョン管理を示唆しているようです。

ブラウザーは、Webサーバーの応答、特にhttpヘッダーを読み取ることにより、何をキャッシュし、何をキャッシュしないかを十分に認識している必要があります-このリソースはどのくらい有効ですか?このリソースは最後に取得してから更新されましたか?etcetera。

「正しく」設定されている場合、アプリケーションのファイルを更新するだけで(ある時点で)ブラウザのキャッシュが更新されます。たとえば、ブラウザーにファイルをキャッシュしないように指示するようにWebサーバーを構成できます(これは悪い考えです)。

それがどのように機能するかについてのより詳細な説明はこちらです https://www.mnot.net/cache_docs/#WORK


3

ハードリロードを実行する場所にこのコードを追加するだけです(ブラウザにキャッシュされたCSS / JSファイルを強制的にリロードさます) .load内でこれを実行して、ループのように更新されないようにします

 $( window ).load(function() {
   location.reload(true);
});

Chromeでは動作しません。ディスクキャッシュからのアセットのロード
Jason Kim

3

サーバー側のコードを使用してファイルの日付を追加するだけです...そのようにしてファイルがキャッシュされ、ファイルが変更されたときにのみ再ロードされます

ASP.NET

<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />

<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>    

これは次のように簡略化できます。

<script src="<%= Page.ResolveClientUrlUnique("~/js/custom.js") %>" type="text/javascript"></script>

プロジェクトに拡張メソッドを追加して、Pageを拡張します。

public static class Extension_Methods
{
    public static string ResolveClientUrlUnique(this System.Web.UI.Page oPg, string sRelPath)
    {
        string sFilePath = oPg.Server.MapPath(sRelPath);
        string sLastDate = System.IO.File.GetLastWriteTime(sFilePath).ToString();
        string sDateHashed = System.Text.RegularExpressions.Regex.Replace(sLastDate, "[^0-9]", "");

        return oPg.ResolveClientUrl(sRelPath) + "?d=" + sDateHashed;
    }
}

2

次のプロセスを実装することをお勧めします。

  • デプロイするたびにcss / jsファイルにバージョンを付けます。例:screen.1233.css(バージョン管理システムを使用している場合、この番号はSVNリビジョンの場合があります)

  • ロード時間を最適化するためにそれらを縮小します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.