私はいくつかのブラウザ(特にFirefoxとOpera)が .css と .js ファイルのキャッシュされたコピーを使うことに非常に熱心であることに気づいた、ブラウザセッションの間でさえ。これらのファイルのいずれかを更新しても、ユーザーのブラウザがキャッシュコピーを使用し続けると、問題が発生します。
問題は、ファイルが変更されたときにユーザーのブラウザにそのファイルを強制的に再ロードさせる最もエレガントな方法は何ですか?
理想的には、このソリューションでは、ページにアクセスするたびにブラウザにファイルを強制的に再ロードさせることはありません。私は答えとして私自身の解決策を投稿するつもりですが、誰かがより良い解決策を持っているのであれば私は興味がありますそして私はあなたの投票を決定させます。
更新:
しばらくここで議論を許した後に、 John Millikin および da5id の提案が有用であることがわかりました。これには、次のような用語があります。 自動バージョン管理 。
以下に新しい答えを投稿しました。これは私の最初の解決策とJohnの提案を組み合わせたものです。
SCdF によって提案されたもう一つのアイデアは、偽のクエリ文字列をファイルに追加することです。 (タイムスタンプを偽の問い合わせ文字列として自動的に使用するPythonコードの一部は pi によって送信されました。)ただし、ブラウザがクエリ文字列を使用してファイルをキャッシュするかどうかについては、いくつかの議論があります。 (覚えておいて、私たちはブラウザがファイルをキャッシュして将来の訪問の際にそれを使うことを望んでいます。ファイルが変更されたときだけ再びそれをフェッチすることを望みます。)
偽のクエリ文字列で何が起こるかは明確ではないので、私はその答えを受け入れていません。
更新: John Millikin および da5id からの提案を組み込むように書き直されました。この解決策はPHPで書かれていますが、他の言語にも容易に適応できるはずです。
更新2: Nick Johnsonからのコメントの組み込み 元の.htaccess
regexはjson-1.3.js
のようなファイルで問題を起こす可能性があること。解決策は、末尾に正確に10桁ある場合にのみ書き換えることです。 (10桁は2001年9月9日から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でも動作します。動的に生成されないものは基本的に何でも。
簡単なクライアントサイドテクニック
一般に、キャッシュは有効です。したがって、Webサイトを開発するときに問題を自分で解決するのか、それとも本番環境でキャッシュを制御しようとしているのかに応じて、2つの手法があります。
あなたのウェブサイトへの一般の訪問者はあなたがそのサイトを開発しているときにあなたが経験しているのと同じ経験を持つことはないでしょう。平均的な訪問者はあまり頻繁にサイトに来ないので(たぶん月に数回、あなたがグーグルまたはhi5ネットワークでなければ)、彼らはあなたのファイルをキャッシュに入れる可能性が低く、それで十分かもしれません。ブラウザに新しいバージョンを強制する場合は、いつでもクエリ文字列をリクエストに追加し、大きな変更を加えるときにバージョン番号を上げることができます。
<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"です。それは主題への非常に良い紹介です。
Apacheのグーグルの mod_pagespeed プラグインはあなたのために自動バージョン管理をするでしょう。本当に滑りやすいです。
Webサーバーから出る途中でHTMLを解析し(PHP、Rails、python、静的HTMLなどに対応)、CSS、JS、画像ファイルへのリンクを書き換えてIDコードを含めます。それはそれらを非常に長いキャッシュ制御で修正されたURLでファイルを提供します。ファイルが変更されると自動的にURLが変更されるため、ブラウザはそれらを再取得する必要があります。基本的には動作しますが、コードを変更することはありません。それは出て行く途中であなたのコードも縮小するでしょう。
バージョンを手動で変更する代わりに、実際のCSSファイルのMD5ハッシュを使用することをお勧めします。
だからあなたのURLはのようなものになります
http://mysite.com/css/[md5_hash_here]/style.css
それでも、書き換え規則を使用してハッシュを削除することはできますが、URLが同じであればファイルは変更されないことを意味するため、キャッシュポリシーを "永久キャッシュ"に設定できるという利点があります。
その後、ファイルのハッシュを計算してタグを更新する簡単なシェルスクリプトを作成できます(含めるために別のファイルに移動することをお勧めします)。
CSSが変わるたびにそのスクリプトを実行するだけでいいのです。ファイルが変更された場合にのみ、ブラウザはファイルをリロードします。編集して元に戻しても、訪問者が再ダウンロードしないようにするためにどのバージョンに戻る必要があるかを判断するのに苦労することはありません。
なぜこのソリューションを実装するのに苦労しているのかわからない。
ファイルの変更されたタイムスタンプを取得し、それをファイルへのクエリ文字列として追加する場合に必要なことはすべて
PHPでは、次のようにします。
<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">
filemtimeはファイル修正タイムスタンプを返すPHP関数です。
?foo=1234
をcss/jsインポートの最後に置くだけで、1234を好きなものに変更できます。例としてSO htmlソースをご覧ください。
そこにあるアイデアは?とにかくパラメータはリクエストで破棄/無視され、新しいバージョンをロールアウトするときにその番号を変更できます。
注:これがキャッシングにどのように影響するかについて、いくつかの議論があります。一般的な要点は、パラメータの有無にかかわらずGETリクエストはキャッシュ可能であるため、上記の解決策が機能することです。
ただし、仕様のその部分を遵守するかどうか、およびユーザーが使用するブラウザを決定するかどうかは、Webサーバーに委ねられています。
私はこれを「自動バージョン管理」と呼んでいます。最も一般的な方法は、静的ファイルのmtimeをURLのどこかに含め、書き換えハンドラまたはURL confsを使用して削除することです。
また見なさい:
30ほどの既存の回答は、2008年頃のWebサイトにとって素晴らしいアドバイスです。ただし、最新の単一ページアプリケーション(SPA)については、いくつかの基本的な前提を再考するときがあります。具体的には、 Webサーバーがファイルの単一の最新バージョンのみを提供することが望ましい。
あなたがブラウザにロードされたSPAのバージョンMを持っているユーザーを想像してください:
/some.template
を取得します。/some.template
の内容で応答します—テンプレートのバージョンMまたはNを返しますか?/some.template
の形式がバージョン間で変更された場合MとN(またはファイルの名前が変更されたなど)おそらく、古いバージョンを実行しているブラウザに送信されるテンプレートのバージョンNは必要ありませんM the parser。†
次の2つの条件が満たされると、Webアプリはこの問題に遭遇します。
アプリが複数のバージョンを並行して提供する必要がある場合、キャッシングと「リロード」の解決は簡単になります:
/v<release_tag_1>/…files…
、/v<release_tag_2>/…files…
<script>
および<link>
タグなどを更新して、バージョン管理されたディレクトリのいずれかでそのファイルを指すようにしますサーバー側またはクライアント側のコードのすべてのURLに対してURLビルダーを呼び出す必要があるため、この最後の手順は難しいように思えます。または、 <base>
タグ を巧みに使用して、現在のバージョンを1か所で変更することもできます。
†これを回避する1つの方法は、新しいバージョンがリリースされたときにブラウザにすべてを強制的にリロードさせることを積極的に行うことです。ただし、進行中の操作を完了するために、少なくとも2つのバージョン(v-currentとv-previous)を並行してサポートするのが最も簡単な場合があります。
Foo.cssを使用しないでください?version = 1!ブラウザはGET変数でURLをキャッシュすることになっていません。 http://www.thinkvitamin.com/features/webapps/serving-javascript-fast によると、IEとFirefoxはこれを無視しますが、OperaとSafariは無視します。代わりに、foo.v1234.cssを使い、書き換え規則を使ってバージョン番号を取り除いてください。
RewriteRuleは、最後にドット表記法のバージョン管理を含むjsまたはcssファイルのための小さなアップデートを必要とします。例えば。 json-1.3.js.
正規表現so .numberにドット否定クラス[^。]を追加しました。無視されます。
RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
ASP.NET 4.5以降では スクリプトバンドリング を使用できます。
リクエスト
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
はバンドルAllMyScriptsに対するもので、クエリ文字列ペアv = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81を含みます。クエリ文字列vには、キャッシュに使用される一意の識別子である値トークンがあります。バンドルが変更されない限り、ASP.NETアプリケーションはこのトークンを使用してAllMyScriptsバンドルを要求します。バンドル内のファイルが変更された場合、ASP.NET最適化フレームワークは新しいトークンを生成し、ブラウザがそのバンドルを要求したときに最新のバンドルが取得されるようにします。
縮小による初回のページロードでのパフォーマンスの向上など、バンドリングには他にも利点があります。
これが純粋な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ファイルの内容の短いHASHを(ファイルのdatetimeの代わりに)計算することです。
これにより、次のようになります。
<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />
もちろん、datetimeのソリューションはCSSファイルを編集する場合にもうまくいきますが、それはcssファイルの内容に関するもので、ファイルの日時に関するものではないと思います。
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'))}}">
スクリプトノード(または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>
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;
}
}
}
}
歓声とありがとう。
次のようにCSS/JS URLを使って乱数を追加するだけです。
example.css?randomNo=Math.random()
利用可能なファイルがあるとします。
/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のDefaultServlet
に委任し、.css
、.js
などのファイルが変更されていない場合、通常304になります)。デプロイメントモードでは "cache forever"と言うヘッダを設定しました。
Js/cssファイルの誤ったパラメータとしてsession-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>
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();
}
...
}
google chromeには Hard Reload と Empty CacheおよびHard Reload のオプションがあります。リロードボタン(Inspectモード)をクリックしたままにすると選択できます。
私は最近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ファイルに触れると自動的にキャッシュ無効化を引き起こすでしょう。非常にうまく機能し、オーバーヘッドは目立ちません。
私の開発のために、私はクロムが素晴らしい解決策を持っていると思います。
https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload
開発者ツールを開いた状態で、更新ボタンを長押しするだけで、「空のキャッシュとハードリロード」の上にマウスを移動して放します。
これは私の親友です、そして、あなたが欲しいものを手に入れるための超軽量の方法です!
私はこの答えをSilverStripe http://www.silverstripe.org 特定の答えとして追加していますが、私は探していて見つけたことはありませんでしたが、 http:// apiと答えました。 silverstripe.org/3.0/source-class-SS_Datetime.html#98-110
うまくいけば、これは誰かがSilverStripeテンプレートを使っていて、各ページにキャッシュされた画像を強制的に再ロードしようとするのを助けてくれるでしょう。私の場合、それは一度だけ再生されるgifアニメーションなので、キャッシュされた後は再生されませんでした。私のテンプレートで私は単に追加しました:
?$Now.Format(dmYHis)
ファイルパスの末尾まで移動すると、一意のタイムスタンプが作成され、ブラウザで新しいファイルとして処理されます。
デッドスレッドを取り戻して申し訳ありません。
@ TomA 正しいです。
"querystring"メソッドを使用しても、 Steve Souders の引用に従ってキャッシュされません。
...一般的なプロキシであるSquidは、クエリ文字列でリソースをキャッシュしません。
@ TomA style.TIMESTAMP.cssを使用することの提案は良いですが、MD5は内容が本当に変更されたときだけ、MD5も同様に変更されます。
ここでのすべての答えは、ネーミングスキームのある種のバージョン管理を示唆しているようです。
ブラウザは、Webサーバの応答、特にhttpヘッダを読み取ることによって、何をキャッシュし、何をキャッシュしないかについて十分に認識している必要があります。このリソースは最後に取得してから更新されたものですか? etcetera。
正しく設定されている場合は、アプリケーションのファイルを更新するだけで(ある時点で)ブラウザのキャッシュが更新されるはずです。たとえば、ファイルをキャッシュしないようにブラウザに指示するようにWebサーバーを設定できます(これは悪い考えです)。
それがどのように機能するかについてのより詳細な説明はここにあります https://www.mnot.net/cache_docs/#WORK
ファイルの内容のMD5ハッシュをそのURLに入れました。そうすれば、非常に長い有効期限を設定でき、ユーザーが古いJSやCSSを持っていることを心配する必要がなくなります。
また、実行時(またはファイルシステムの変更時)にファイルごとに1回計算するので、設計時またはビルドプロセス中に行うことは面白いことではありません。
あなたがASP.NET MVCを使っているなら、あなたはコードをチェックアウトすることができます ここに私の他の答えで 。
ファイルの日付を追加するには、サーバー側のコードを使用してください。そうすれば、ファイルが変更されたときにのみキャッシュされて再ロードされます
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;
}
}
以下のプロセスを実行することをお勧めします。
screen.1233.css(バージョン管理システムを使用している場合は、番号はSVNのリビジョンになります)
読み込み時間を最適化するためにそれらを縮小する
Javaサーブレット環境の場合は、 Jawrライブラリ を見ることができます。機能ページでは、キャッシュの処理方法について説明しています。
Jawrは、クライアントにリソースのキャッシュを強制するように最善を尽くします。ファイルが変更されたかどうかをブラウザが尋ねると、304(変更されていない)ヘッダが内容なしで返送されます。一方、Jawrを使用すると、バンドルの新しいバージョンがすべてのクライアントによってダウンロードされることを100%保証できます。リソースへのすべてのURLには、自動的に生成されたコンテンツベースのプレフィックスが含まれます。このプレフィックスは、結果が更新されるたびに自動的に変更されます。新しいバージョンをデプロイすると、バンドルへのURLも変更されるため、クライアントが古いキャッシュバージョンを使用することは不可能になります。
ライブラリはjs/cssの縮小も行いますが、望まない場合はオフにすることができます。
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;
このコードを追加するだけで、ハードリロードを行います(ブラウザにキャッシュされたCSS/JSファイルを強制的にリロードさせます)。 これを.load内で実行し、ループのように更新されないようにします。
$( window ).load(function() {
location.reload(true);
});
最新のブラウザを使用している場合は、マニフェストファイルを使用して、更新する必要があるファイルをブラウザに通知できます。これは、ヘッダ、URLのバージョンなどを必要としません。
詳細については、以下を参照してください。 https://developer.mozilla.org/nl/docs/Web/HTML/Applicatie_cache_gebruiken#Introduction
私はリソースURLにタイムスタンプベースまたはハッシュベースの微分器を使用するアプローチに問題があると思います。例えばへのリンクを含むページ。スタイルシート も同様にキャッシュされる可能性があります 。そのため、キャッシュされたページは古いバージョンのスタイルシートを要求する可能性がありますが、要求されたページでは動作する可能性があるまたは動作しない可能性がある最新バージョンが提供されます。
これを修正するには、リクエストしているページをno-cache
ヘッダーまたはメタで保護して、すべてのロードで確実に更新されるようにする必要があります。または、リクエストしたページがスタイルファイルのバージョンを取得できるように、サーバーにデプロイしたスタイルファイルの すべてのバージョン をそれぞれ個別のファイルとして、それらを区別せずに維持する必要がありますのために設計されました。後者の場合、基本的にHTMLページとスタイルシートのバージョンを結び付けます。これは静的に行うことができ、サーバーロジックを必要としません。
"SCdFによって提案されたもう一つのアイデアは、偽のクエリ文字列をファイルに追加することです。(タイムスタンプを自動的に偽のクエリ文字列として使用するPythonコードがpiから提出されました。)ブラウザがファイルをクエリ文字列でキャッシュするわけではありません(ブラウザにファイルをキャッシュさせ、将来の訪問時にそれを使用させることを忘れないでください。偽のクエリ文字列で何が起こるか、私はその答えを受け入れていません。」
<link rel = "スタイルシート" href = "file.css?<?= hash_hmac( 'sha1'、session_id()、md5_file(" file.css "));?>" />
ファイルをハッシュすると、ファイルが変更されたときにクエリ文字列も変更されます。そうでなければ、それは変わりません。セッションごとにリロードも強制されます。
必要に応じて、書き換えを使ってブラウザに新しいURIだと思わせることもできます。
Script.jsのキャッシュを無効にする ローカル開発の場合のみ pure JSでは
ランダムにscript.jsを挿入しますか?wizardry = 1231234そして通常のscript.jsをブロックします
<script type="text/javascript">
if(document.location.href.indexOf('localhost') !== -1) {
const scr = document.createElement('script');
document.setAttribute('type', 'text/javascript');
document.setAttribute('src', 'scripts.js' + '?wizardry=' + Math.random());
document.head.appendChild(scr);
document.write('<script type="application/x-suppress">'); // prevent next script(from other SO answer)
}
</script>
<script type="text/javascript" src="scripts.js">
ASP.Net Webサイトに対する別の提案
必要なファイルをすべてリストした単一のindex.htmlしかない、SPA用のソリューションを探すときに、私はこの問題に遭遇しました。私は私を助けたいくつかのリードを得ましたが、私は迅速で簡単な解決策を見つけることができませんでした。
最後に、私は出版プロセスの一環としてhtml/js index.htmlを自動バージョン化するのに必要なクイックページ(すべてのコードを含む)を書きました。それは完全に動作し、最後に変更された日付に基づいて新しいファイルを更新するだけです。
私の投稿は http://blueskycont.com/wp/2016/05/12/autoversion-your-spa-index-html/ で見ることができます。そこにはフリーワーキングもあります。
コードの内容は
private void ParseIndex(string inFile, string addPath, string outFile)
{
string path = Path.GetDirectoryName(inFile);
HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
document.Load(inFile);
foreach (HtmlNode link in document.DocumentNode.Descendants("script"))
{
if (link.Attributes["src"]!=null)
{
resetQueryString(path, addPath, link, "src");
}
}
foreach (HtmlNode link in document.DocumentNode.Descendants("link"))
{
if (link.Attributes["href"] != null && link.Attributes["type"] != null)
{
if (link.Attributes["type"].Value == "text/css" || link.Attributes["type"].Value == "text/html")
{
resetQueryString(path, addPath, link, "href");
}
}
}
document.Save(outFile);
MessageBox.Show("Your file has been processed.", "Autoversion complete");
}
private void resetQueryString(string path, string addPath, HtmlNode link, string attrType)
{
string currFileName = link.Attributes[attrType].Value;
string uripath = currFileName;
if (currFileName.Contains('?')) uripath = currFileName.Substring(0, currFileName.IndexOf('?'));
string baseFile = Path.Combine(path, uripath);
if (!File.Exists(baseFile)) baseFile = Path.Combine(addPath, uripath);
if (!File.Exists(baseFile)) return;
DateTime lastModified = System.IO.File.GetLastWriteTime(baseFile);
link.Attributes[attrType].Value = uripath + "?v=" + lastModified.ToString("yyyyMMddhhmm");
}
ここでの多くの回答は、URLにタイムスタンプを追加することを提唱しています。プロダクションファイルを直接変更しているのでなければ、ファイルのタイムスタンプはファイルが変更された時刻を反映する可能性は低いです。ほとんどの場合、これによりファイル自体よりもURLが頻繁に変更されます。これが、levikや他の人が示唆しているようにMD5などのファイルの内容の高速ハッシュを使用する必要がある理由です。
値は、ファイルが要求されるたびにではなく、構築時または実行時に1回計算する必要があることに注意してください。
例として、stdinからファイル名のリストを読み取り、ハッシュを含むjsonファイルをstdoutに書き込む単純なbashスクリプトがあります。
#!/bin/bash
# create a json map from filenames to md5s
# run as hashes.sh < inputfile.list > outputfile.json
echo "{"
delim=""
while read l; do
echo "$delim\"$l\": \"`md5 -q $l`\""
delim=","
done
echo "}"
このファイルは、サーバーの起動時にロードされ、ファイルシステムを読み取る代わりに参照される可能性があります。
キャッシュを回避しようとしている開発者の場合、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>
私が知っている最善かつ迅速な方法の1つは、CSSまたはJSファイルがあるフォルダーの名前を変更することです。開発者向けのOR。 CSS/jsファイルの名前をバージョンのように変更します。
<link rel="stylesheet" href="cssfolder/somecssfile-ver-1.css"/>
Jsファイルについても同じことをしてください。
これを行う私の方法は、単純にlink要素をサーバー側に含めることです。
<!--#include virtual="/includes/css-element.txt"-->
css-element.txtの内容は次のとおりです。
<link rel="stylesheet" href="mycss.css"/>
つまり、my-new-css.cssにリンクしたい日など、インクルードを変更するだけです。
既存の回答から少し改善しています...
乱数またはセッションIDを使用すると、リクエストごとにリロードが発生します。理想的には、何らかのjs/cssファイルでコードの変更が行われた場合にのみ変更する必要があるかもしれません。共通JSPファイルを他の多くのjspおよびjsファイルのテンプレートとして使用する場合共通JSPファイルに以下を追加
<%@ taglib prefix="c" uri="http://Java.Sun.com/jsp/jstl/core"%>
<c:set var = "version" scope = "application" value = "1.0.0" />
Jsファイルのインクルードで以下のようにすべての場所で上記の変数を使用してください。
<script src='<spring:url value="/js/myChangedFile.js?version=${version}"/>'></script>
利点:
1)この方法は、1か所だけでバージョン番号を変更するのに役立ちます。
2)適切なバージョン番号(通常はビルド/リリース番号)を維持すると、コードの変更が正しくデプロイされていることを確認または確認するのに役立ちます(ブラウザの開発者コンソールから)。
もう1つの役に立つヒント:
クロムブラウザを使用している場合は、開発ツールが開いているときにキャッシュを無効にすることができます。 ChromeでF12キーを押しながらF1キーを押して、設定>設定>ネットワーク>キャッシュを無効にします(DevToolsが開いている間)。
まあ、私はそれが次のようにJSファイルのバージョンに乱数を追加することにより、各時間のjsに、ページの読み込みをバージョンを変更することで、私のように動作してきました。
// Add it to the top of the page
<?php
srand();
$random_number = Rand();
?>
そして、次のようにjsのバージョンに乱数を適用します。
<script src="file.js?version=<?php echo $random_number;?>"></script>