web-dev-qa-db-ja.com

キャッシュされたCSSデータの強制更新

ブラウザにキャッシュされたCSSを強制的に更新させることは可能ですか?

これは、すべてのリクエストほど単純ではありません。しばらくの間、安定したCSSを使用していたサイトがあります。

ここで、CSSを大幅に更新する必要があります。ただし、CSSをキャッシュしたブラウザは、数日間新しいCSSを受け取らず、レンダリングの問題が発生します。

CSSを強制的に更新する方法はありますか、それともバージョン固有のCSS URLを選択する方が良いでしょうか?

37
Michael Edwards

考慮すべきことがいくつかあり、これにアプローチするさまざまな方法があります。まず、 仕様

私たちは何を達成しようとしていますか?

理想的には、変更されたリソースは、最初に要求されたときに無条件にフェッチされ、その後サーバーと対話することなく期限切れになるまでローカルキャッシュから取得されます。

観察されたキャッシュ動作

さまざまな順列を追跡するのは少しわかりにくいので、次の表を作成しました。これらの監視は、Chrome against IISからのリクエストを作成し、開発者コンソールで応答/動作を監視することによって生成されました。

いずれの場合でも、新しいURLはHTTP 200になります。重要なことは、subequequent要求で何が起こるかです。

+---------------------+--------------------+-------------------------+
|        Type         |   Cache Headers    |     Observed Result     |
+---------------------+--------------------+-------------------------+
| Static filename     | Expiration +1 Year | Taken from cache        |
| Static filename     | Expire immediately | Never caches            |
| Static filename     | None               | HTTP 304 (not modified) |
|                     |                    |                         |
| Static query string | Expiration +1 Year | HTTP 304 (not modified) |
| Static query string | Expire immediately | HTTP 304 (not modified) |
| Static query string | None               | HTTP 304 (not modified) |
|                     |                    |                         |
| Random query string | Expiration +1 Year | Never caches            |
| Random query string | Expire immediately | Never caches            |
| Random query string | None               | Never caches            |
+---------------------+--------------------+-------------------------+

ただし、、ブラウザーとWebサーバーが常に期待どおりに動作するとは限らないことに注意してください。有名な例: 2012年にモバイルSafariがキャッシュを開始しましたPOSTリクエスト 。開発者は満足していませんでした。

クエリ文字列

ASP.Net MVC Razor構文の例ですが、ほとんどすべてのサーバー処理言語に適用できます。

...一部のアプリケーションは従来、クエリURL(rel_path部分に「?」を含む)を使用してGETとHEADを使用して重大な副作用を伴う操作を実行していたため、サーバーは、明示的な有効期限。これは、具体的には、そのようなURIに対するHTTP/1.0サーバーからの応答がキャッシュから取得されるべきではないことを意味します。

HTMLに含まれるCSS URLの末尾にランダムパラメーターを追加すると、新しい要求が強制され、サーバーはHTTP 200(変更されていない場合でも304ではない)で応答する必要があります。

<link href="[email protected]" />

もちろん、クエリ文字列をeveryリクエストでランダム化すると、キャッシュが完全に無効になります。 これは、本番アプリケーションにとってはめったに/決して望ましくありません。

いくつかのURLのみを管理している場合は、ビルド番号または日付を含めるように手動で変更する場合があります。

@{
    var Assembly = Assembly.GetEntryAssembly();
    var name = Assembly.GetName();
    var version = name.Version;
}

<link href="[email protected]" />

これにより、ユーザーエージェントが最初にURLに遭遇したときに新しいリクエストが発生しますが、その後のリクエストはほとんど304を返します。これでもリクエストが行われますが、少なくともファイル全体は提供されません。

パス修正

より良い解決策は、新しいパスを作成することです。少しの努力で、このプロセスを自動化して、パスをバージョン番号(またはその他の一貫した識別子)に書き換えることができます。

この回答 は、Microsoft以外のプラットフォーム用のいくつかのシンプルでエレガントなオプションを示しています。

Microsoft開発者は、特定のファイルタイプに対するすべてのリクエストをインターセプトするHTTPモジュールを使用するか、MVCルート/コントローラーコンボを活用して正しいファイルを提供することができます(これはまだ見ていませんが、実現可能だと思います)。

もちろん、最も簡単な(必ずしも最速または最良とは限らない)方法は、各リリースで問題のファイルの名前を変更し、linkタグ内の更新されたパスを参照することです。

TLDR

  • ファイル名またはクエリ文字列を変更する
  • リリースごとに1回のみ発生する変更を使用する
  • クエリ文字列の変更よりもファイル名の変更が望ましい
  • キャッシングの利点を最大化するために、常にHTTPヘッダーを設定します
53
Tim Medora

CSSファイルの名前を変更することは、はるかに良いアイデアだと思います。すべてのアプリケーションに適しているわけではありませんが、ユーザーがCSSファイルを一度ロードするだけで済むようにします。最後にランダムな文字列を追加すると、毎回ダウンロードする必要があります。上記のjavascriptメソッドとApacheメソッドについても同じことが言えます。簡単な答えが最も効果的な場合もあります。

別の解決策は次のとおりです。

<FilesMatch "\.(js|css)$">
    Header set Cache-Control "max-age=86400, public"
</FilesMatch>

これにより、最大キャッシュ期間が1日または86400秒に制限されます。

7
Andy Gee

ティムメドラの回答を最初に読んでください。これは本当に知識が豊富で素晴らしい努力の投稿です。

次に、PHPでどのように行うかを説明します。従来のバージョン管理に煩わされたり、1000ページ以上を維持しようとはしませんが、ユーザーが常に最新バージョンのCSSを取得し、それをキャッシュするようにします。

そのため、クエリ文字列手法とPHP filemtime() を使用して、最後に変更されたタイムスタンプを返します。

この関数は、ファイルのデータブロックが書き込まれていた時間、つまりファイルの内容が変更された時間を返します。

私のwebappでは、config.phpファイルを使用して設定を保存するので、ここでは次のような変数を作成します。

$siteCSS = "/css/standard.css?" .filemtime($_SERVER['DOCUMENT_ROOT']. "/css/standard.css");

そして、すべてのページで次のようにCSSを参照します。

<link rel="stylesheet" type="text/css" media="all" href="<?php echo $siteCSS?>" />

これは、これまでのところPHP/IISでうまく機能しています。

0
RobDigital

YuはApacheでできるかもしれません...

<FilesMatch "\.(html|htm|js|css)$">
FileETag None
<IfModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</IfModule>
</FilesMatch>
0
Aaron R