web-dev-qa-db-ja.com

ファイルキャッシュ:クエリ文字列と最終変更日

私は自分のウェブサイトのアセットをキャッシュする方法にだまされており、私のものに似たほとんどのウェブサイトがクエリ文字列を使用してキャッシュをオーバーライドしていることに気付きました(例:/css/style.css?v=124942823)

その後、style.cssファイルを保存するたびに、最後に変更されたヘッダーが「更新」され、クエリ文字列が不要になることに気付きました。

だから私は疑問に思う:

  • なぜ多くのWebサイトが、最後に変更されたヘッダーに機能させるだけでなく、「クエリ文字列」メソッドを使用するのですか?
  • Last-modifiedヘッダーの設定を解除して、クエリ文字列を操作する必要がありますか? (これには特別な利点がありますか?)
33
Tom

TL; DR

なぜ多くのWebサイトが、最後に変更されたヘッダーに機能させるのではなく、「クエリ文字列」メソッドを使用するのですか?

クエリ文字列を変更するとURLが変更され、コンテンツが「新鮮」になります。

Last-modifiedヘッダーの設定を解除して、クエリ文字列を操作する必要がありますか?

いいえ。それはほとんど正しい答えですが。


Webで使用される3つの基本的なキャッシュ戦略があります。

  • キャッシングなし、またはキャッシングが無効
  • 検証/条件付きリクエストを使用する
  • 永遠にキャッシング

3つすべてを説明するために、次のシナリオを検討してください。

ユーザーが初めてWebサイトにアクセスし、10ページをロードして離脱します。各ページは同じcssファイルをロードします。上記のキャッシュ戦略のそれぞれについて、いくつのリクエストが行われますか?

キャッシュなし:10リクエスト

このシナリオでは、結果に影響するものが他にないことは明らかです。cssファイルに対する10回のリクエストは、クライアント(ブラウザ)に10回送信されます。

長所

  • 常に新鮮なコンテンツ
  • 労力/管理は不要

短所

  • 効率が最も低く、常にコンテンツが転送される

検証リクエスト:10リクエスト

Last-Modified または Etag が使用されている場合、also10個のリクエストがあります。ただし、そのうちの9つはヘッダーにすぎず、本文は転送されません。クライアントは条件付きリクエストを使用して、既に持っているものを再度ダウンロードすることを避けます。たとえば、このサイトのcssファイルをご覧ください。

ファイルが最初に要求されると、次のことが起こります。

$ curl -i http://cdn.sstatic.net/stackoverflow/all.css
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:38:31 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d3fa9eddf76d614f83603a42f3e552f961399880311549; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:38:31 GMT
CF-RAY: 1294f50b2d6b08de-CDG
.avatar-change:hover{backgro.....Some KB of content

同じURLに対する後続のリクエストは次のようになります。

$ curl -i -H "If-Modified-Since:Wed, 30 Apr 2014 22:09:37 GMT" http://cdn.sstatic.net/stackoverflow/all.css
HTTP/1.1 304 Not Modified
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:40:11 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d0cc5afd385060dd8ba26265f0ebf40f81399880411024; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:40:11 GMT
CF-RAY: 1294f778e75d04a3-CDG

本文がなく、応答が 4 Not Modified であることに注意してください。これは、そのURLに対して既に(ローカルキャッシュに)あるコンテンツがまだ新鮮であることをクライアントに伝えています。

これが最適なシナリオであると言っているわけではありません。 chrome開発者ツール のネットワークタブ)などのツールを使用すると、リクエストにかかる正確な時間を確認できます。

enter image description here

応答には本文がないため、転送するデータが少ないため、応答時間ははるかに短くなります。ただし、isはまだ応答です。そして、そこにisがまだリモートサーバーに接続するオーバーヘッドのすべてです。

長所

  • 常に新鮮なコンテンツ
  • 1つの「フル」リクエストのみが送信されました
  • 9つのリクエストは、ヘッダーのみを含む非常にスリムです
  • もっと効率的

短所

  • それでもリクエストの最大数を発行します
  • それでもDNSルックアップが発生します
  • それでもリモートサーバーへの接続を確立する必要があります
  • オフラインでは機能しません
  • サーバー構成が必要な場合があります

永遠にキャッシュする:1リクエスト

Etagがなく、最後に変更されたヘッダーがなく、期限が切れるヘッダーのみが将来的に設定される場合-URLへの最初のアクセスのみがリモートサーバーとの通信になります。これは よく知られていますか?フロントエンドのパフォーマンス向上のためのベストプラクティス です。この場合、後続のリクエストでは、クライアントは自身のキャッシュからコンテンツを読み取り、リモートサーバーとはまったく通信しません。

これには明確なパフォーマンス上の利点があります。これは、レイテンシーが大きくなる可能性のあるモバイルデバイスで特に重要です(軽度に言えば)。

長所

  • 最も効率的なコンテンツは一度だけ転送されます

短所

  • Urlmustを変更して、既存の訪問者が古いキャッシュバージョンをロードしないようにします
  • セットアップ/管理のほとんどの努力

キャッシュの無効化にクエリ文字列を使用しないでください

サイトがクエリ引数を使用するのは、クライアントのキャッシュを回避するためです。コンテンツが変更されると(またはサイトの新しいバージョンが公開されると)、クエリ引数が変更されるため、URLが変更されると、そのファイルのnewバージョンが要求されます。これは、ファイルを変更するたびにファイル名を変更するよりも作業が少なく便利です。ただし、問題がないわけではありません。

クエリ文字列を使用するとプロキシキャッシュが防止されます 、以下の引用では、著者はbrowser <-> proxy cache server <-> websiteからのリクエストがプロキシキャッシュを使用しないことを実証しています:

Mylogo.gif?v = 1.2を2回ロード(間にキャッシュをクリア)すると、次のヘッダーが生成されます。

>> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1
<< HTTP/1.0 200 OK
<< Date: Sat, 23 Aug 2008 00:19:34 GMT
<< Expires: Tue, 21 Aug 2018 00:19:34 GMT
<< X-Cache: MISS from someserver.com
<< X-Cache-Lookup: MISS from someserver.com

>> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1
<< HTTP/1.0 200 OK
<< Date: Sat, 23 Aug 2008 00:19:47 GMT
<< Expires: Tue, 21 Aug 2018 00:19:47 GMT
<< X-Cache: MISS from someserver.com
<< X-Cache-Lookup: MISS from someserver.com

ここでは、2番目の応答がプロキシによって処理されなかったことは明らかです。キャッシング応答ヘッダーにMISSと表示され、DateとExpiresの値が変更され、stevesouders.comアクセスログの末尾に2つのヒットが表示されます。

これを軽視すべきではありません。物理的に世界の反対側にあるWebサイトにアクセスする場合、応答時間が非常に遅くなる可能性があります。ルートに沿って配置されたプロキシサーバーから回答を取得することは、Webサイトが使用可能かどうかの違いを意味する可能性があります-キャッシュされたリソースの場合は、URLの最初の読み込みが遅く、検証要求を使用する場合はサイト全体が遅くなることを意味します。

代わりにバージョン管理アセット

「最良の」解決策は、コンテンツが変更されるたびにURLも変更されるようにファイルをバージョン管理することです。通常、それはビルドプロセスの一部として自動化されます。

ただし、それに近い妥協点は、書き換えルールを実装することです など

# ------------------------------------------------------------------------------
# | Filename-based cache busting                                               |
# ------------------------------------------------------------------------------

# If you're not using a build process to manage your filename version revving,
# you might want to consider enabling the following directives to route all
# requests such as `/css/style.12345.css` to `/css/style.css`.

# To understand why this is important and a better idea than `*.css?v231`, read:
# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring

<IfModule mod_rewrite.c>
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L]
</IfModule>

このようにして、サーバーはfoo.123.cssのリクエストをfoo.cssとして処理します。これには、キャッシュの無効化にクエリパラメーターを使用する利点がすべてありますが、withoutプロキシキャッシングを無効にする問題。

64
AD7six

Last-Modifiedヘッダーはブラウザー間で異なる方法で適用されますが、通常、ブラウザーは条件付きGET要求を発行し、キャッシュを更新する必要がある場合にサーバーが応答する必要があります。たとえば、Firefoxでは...

「Last-Modified」応答ヘッダーは、弱いバリデーターとして使用できます。 1秒の解像度しかないため、弱いと見なされます。応答に「Last-Modified」ヘッダーが存在する場合、クライアントは「If-Modified-Since」リクエストヘッダーを発行して、キャッシュされたドキュメントを検証できます。

検証要求が行われると、サーバーは通常の200 OKで検証要求と応答を無視するか、キャッシュされたコピーを使用するようブラウザーに指示するために304 Not Modifiedを返すことができます。後者の応答には、キャッシュされたドキュメントの有効期限を更新するヘッダーを含めることもできます。

タイムスタンプ(またはフィンガープリント)を設定することにより、キャッシュを更新する必要があることをブラウザに明示的に通知し、非常に長い有効期限を設定できます。

Railsアセットパイプライン( http://guides.rubyonrails.org/asset_pipeline.html )のドキュメントでは、フィンガープリントの利点が3つ挙げられていることに注意してください。クエリ文字列のタイムスタンプ:

  • ファイル名がクエリパラメータによってのみ異なる場合、すべてのキャッシュがコンテンツを確実にキャッシュするとは限りません。
  • ファイル名は、マルチサーバー環境のノード間で変更できます。
  • キャッシュの無効化が多すぎる

キャッシュの詳細とベストプラクティス: https://developers.google.com/speed/docs/best-practices/caching

2
Vinnie Pepi