ホームページ >ウェブフロントエンド >htmlチュートリアル >キャッシュについて話すとき、何を話しますか_html/css_WEB-ITnose
TL;DR
前の段落の内容は基本概念の紹介です。時間がない学生は、この内容を一番下にドラッグすることをお勧めします。それを読むために。
Web キャッシュは、一般的なドキュメントのコピーを自動的に保存する HTTP デバイス です。はい、キャッシュについて話すときは、ブラウザーやプロキシ キャッシュ サーバーなどのデバイスを指します。
ネットワーク経由でのコンテンツの取得は遅く、コストがかかります。大規模な応答にはクライアントとサーバーの間で複数回の往復が必要となり、ブラウザがコンテンツを使用して処理するのにかかる時間も長くなります。訪問者のデータ通信料。したがって、以前に取得したリソースをキャッシュして再利用する機能は、パフォーマンスを最適化する上で重要な側面になります。
キャッシュを使用すると、次の利点があります。
キャッシュ 冗長なデータ送信が削減され 、ネットワーク コストが節約されます。
キャッシュ ネットワークのボトルネックの問題を軽減し、より多くの帯域幅を必要とせずにページをより速く読み込むことができます。
キャッシュ 元のサーバーの要件を軽減します。サーバーはより速く応答し、過負荷を回避できます。
キャッシュ遠方からのページの読み込みが遅くなるため、距離の遅延が減少します。
ドキュメントをキャッシュしない小規模な Web サイトが多数あるため、クライアントは毎回同じドキュメント (jQuery.js など) にアクセスします。同時に、同じドキュメントをサーバーからローカル クライアントにダウンロードする必要があり、大量の冗長なデータ送信が発生します。
キャッシュにより、ワイド エリア ネットワークの帯域幅が制限されるというボトルネックの問題が軽減されます。多くのネットワークは、リモート サーバーよりもローカル クライアントに広い帯域幅を提供します。クライアントが高速 LAN 上のキャッシュからコピーを取得できれば、パフォーマンスは当然向上します。
12306 の春節旅行ラッシュ、Weibo の春節祝賀紅包などはすべてこの状況に遭遇します。 12306 チケット発売時間帯はチケットを求めて多くの利用者が殺到し、瞬間的に混雑が発生します。一時的な混雑により、ネットワークや Web サーバーがクラッシュする可能性があります。 DDOSについても同様です。
タオバオのメインサーバーが杭州のサーバーに配置されていると仮定します。米国の顧客が淘宝網を開くときは、淘宝網のホームページをダウンロードし、データが光の速さで送信されることを前提とする必要があります。杭州からワシントンまでの距離は約 14,000 キロメートルなので、光の速さ自体は送信に約 90 ミリ秒かかります (リクエストと返信の時間を含む)。タオバオのページに写真が 20 枚しかない場合、1 回の接続で送信できます。約 1980 ミリ秒のレイテンシが必要です (接続要求を開く 90 ミリ秒 + Web ページの取得 90 ミリ秒 + すべての画像の取得 90 * 20 = 1800 ミリ秒)。これは単なる遅延であることに注意してください。つまり、この距離での 20 枚の写真は、クライアントのローカル要求に比べて約 2 秒遅れることになります。
キャッシュ ヒット (キャッシュ ヒット) コピーを使用できるキャッシュされたデバイス (プロキシ キャッシュ サーバーまたはローカル マシン) があります。
キャッシュミス キャッシュされたデバイスに利用可能なレプリカがない場合、リクエストはオリジンサーバーに転送されます。
サーバー上のテキストコンテンツはいつでも変更される可能性があります。たとえば、淘宝網のホームページ上のファイルには記録機能を追加する必要があります。ユーザーのクリックログが記録されるため、特定の js ファイルを変更して対応する機能を追加する必要があります。この場合、キャッシュは保存したコピーがサーバー上の最新のコピーであるかどうかを時々チェックします。この種の検出は 鮮度検出 と呼ばれ、これらの鮮度チェックは HTTP 再検証 と呼ばれます。
効果的に再検証するために、HTTP はサーバーからオブジェクト全体を取得しなくても、コンテンツが最新であるかどうかを迅速に検出できるいくつかの特別なリクエストを定義します。最も一般的に使用されるのは、If-Modified-Since ヘッダーです (ETag と If-None-Match については後述します)。このヘッダーが GET リクエストに追加されると、オブジェクトのコピーをキャッシュして変更した場合にのみオブジェクトが送信されることがサーバーに通知されます。
サーバーが GET If-Modified-Since リクエストを受信すると、次の 3 つの状況が発生する可能性があります:
サーバー オブジェクトが変更されていない場合、サーバーは小さな HTTP 304 Not Modified 応答をクライアントに送り返します。
サーバー オブジェクトがキャッシュされたコピーと異なる場合、サーバーはプレーンな完全なメッセージをクライアントに送信します HTTP 200 OK応答。
サーバー オブジェクトが削除された場合、サーバーは 404 Not Found 応答を送り返し、キャッシュはそのコピーを削除します。
If-Modified-Since は、Last-Modified サーバー応答ヘッダーと連携して動作する HTTP 要求ヘッダーです。オリジンサーバーは、提供されたドキュメントに最終変更日を追加します。キャッシュがキャッシュされたドキュメントを再検証すると、キャッシュされたコピーが最後に変更された日付を含む If-Modified-Since ヘッダーが含まれます。
<!-- test.html 最后一次修改时间: 2016-3-12 20:03 --><!Doctype html><html><head> <title>hello</title></head><body> <div>no cache</div></body></html>
// demo1.js 'use strict'const http = require('http')const fs = require('fs')const onRequest = (req, res) => { const filepath = './test.html' , file = fs.readFileSync(filepath) , stats = fs.statSync(filepath) , mtime = stats.mtime , reqMtimeString = req.headers["if-modified-since"] let status = 200 if(reqMtimeString) { const reqMtime = new Date(reqMtimeString) if(reqMtime.getTime() === mtime.getTime()) status = 304 } res.writeHead(status, {'Content-Type': 'text/html', 'Last-Modified': mtime}) if(200 === status) res.write(file) res.end()}http.createServer(onRequest).listen('8000', () => console.log('server start:8000'))
上記は、test.html が変更されたかどうかを検出するために Node.js で書かれた単純なサーバーです。最終変更時刻がクライアント時刻と異なる場合は、新しい時刻が返されます。 。 書類。
ノードdemo.js経由でサーバーを実行します。ブラウザの開発者ツールを開くと (キャッシュを無効にするオプションを必ずチェックしてください)、この時点での HTTP リクエストのヘッダーが次であることがわかります:
GeneralRequest URL:http://localhost:8000/Request Method:GETStatus Code:200 OKRemote Address:[::1]:8000Response HeadersHTTP/1.1 200 OKContent-Type: text/html...Last-Modified: Sat Mar 12 2016 20:03:58 GMT+0800 (CST)Request HeadersGET / HTTP/1.1Host: localhost:8000...If-Modified-Since: Sat Mar 12 2016 20:03:58 GMT+0800 (CST)
この時点で返されるステータス コードは 200 です。 、サーバー設定 Last-Modified ヘッダーを追加した後、ブラウザーは If-Modified-Since ヘッダーを追加します。次に、ブラウザを更新して開発者ツールを確認すると、一般ヘッダー (つまり、General) のステータス コードが 304 Not Modified に変化することがわかります。これは、前述の 再検証ヒット です。
test.html の内容を変更します。
<!-- test.html 最后一次修改时间: 2016-3-12 20:26 --><!Doctype html><html><head> <title>hello</title></head><body> <div>change cache</div></body></html>
ブラウザを更新します。 このときのヘッダーは次のとおりです。
GeneralRequest URL:http://localhost:8000/Request Method:GETStatus Code:200 OKRemote Address:[::1]:8000Response HeadersHTTP/1.1 200 OKContent-Type: text/html...Last-Modified: Sat Mar 12 2016 20:26:36 GMT+0800 (CST)Request HeadersGET / HTTP/1.1Host: localhost:8000...If-Modified-Since: Sat Mar 12 2016 20:03:58 GMT+0800 (CST)
ステータスが表示されます。一般ヘッダのコードが再び200となり、レスポンスヘッダのLast-Modifiedが最終変更時刻、つまり上記の再検証ミスとなり、サーバーは変更されたファイルを返します。
オブジェクトの削除時にコード検証を記述する必要はありません。
サーバーは、HTTP Cache-Control ヘッダーと Expires ヘッダーを追加して、キャッシュされたドキュメントの有効期限が切れていない場合、キャッシュがそのコピーを自由に使用できるようにすることもできます。
HTTP/1.0 Expires ヘッダーまたは HTTP/1.1 Cache-Control: max-age 応答ヘッダーで有効期限を指定します。 Expires は絶対日付を使用します。絶対日付はコンピューターの時計の正しい設定に依存します。コンピューターの時計が正しくないと、キャッシュされた有効期限が正しくなくなり、キャッシュの本来の目的が達成されない可能性があります。 1.1 - 制御: Expires の代わりに max-age を使用します。
max-age 応答ヘッダーは、ドキュメントがサーバーから送信されてからそのドキュメントが新しいとみなされる秒数を示します。max と同じように動作する s-maxage ヘッダーもあります。 -age 同様ですが、共有キャッシュのみです。
サーバーは、キャッシュにドキュメントをキャッシュしないように要求したり (Cache-Control: no-store)、最大保存期間をゼロに設定したり (Cache-Control: max-age=0) することができます。ドキュメントはアクセスされるたびにキャッシュされます。
以下は、Nodejs に実装された max-age コードの一部です。
// demo2.js'use strict'const http = require('http')const fs = require('fs')const onRequest = (req, res) => { if('/req.js' === req.url) { let filepath = './req.js' , file = fs.readFileSync(filepath) res.writeHead(200, {'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=60'}) res.write(file) res.end() } else { let filepath = './test2.html' , file = fs.readFileSync(filepath) res.writeHead(200, {'Content-Type': 'text/html'}) res.write(file) res.end() }}http.createServer(onRequest).listen('8000', () => console.log('server start:8000'))
// req.js'use strict'console.log(123)
<!-- test2.html --><!Doctype html><html><head> <title>hello</title></head><body> <div>no cache</div><script src='/req.js'></script></body></html>
ブラウザを開き、まず開発者ツールを開いて、アドレスを入力し、 Enter キーを押します。 下の図からわかるように、req.js はキャッシュされません。
ブラウザにアドレスを再入力し、Enter キーを押します (手動更新と cmd+r は強制的に更新され、キャッシュがクリアされます)。図では req.js が確認できます。以下がキャッシュされました (キャッシュから):
サーバーに設定されているキャッシュの有効期限が 60 秒なので、60 秒後に見ると、この時点のキャッシュは期限切れになっており、再び最初の画像のようになります。req .js はキャッシュから来ていません。
HTTP を使用すると、ユーザーは Etag の バージョン識別子 を比較できます。サーバー側で Etag ヘッダーを設定した後、クライアントは対応する If-None-Match ヘッダーを生成します。サーバーは、If-None-Match ヘッダーと、対応するドキュメント コンテンツのハッシュ値またはその他のフィンガープリント情報をチェックすることで、新しいドキュメントを返すかどうかを確認できます。
Etag を使用するため、サーバーは毎回ドキュメントの内容をハッシュして、新しいドキュメントを返すか大量のサーバー リソースを無駄にするかを決定する必要があるため、Etag のキャッシュ戦略はお勧めできません。
Google が提供する最適なキャッシュ戦略と組み合わせると、要約は次のようになります:
HTML はキャッシュなしとしてマークされます。これは、ブラウザーがそれをキャッシュすることを意味します。要求するたびにドキュメントが再検証され、内容が変更された場合は最新バージョンが取得されます。同時に、HTML マークアップで、CSS および JavaScript リソースの URL にフィンガープリントを埋め込みます。これらのファイルのコンテンツが変更されると、ページの HTML も変更され、HTML 応答の新しいコピーが作成されます。ダウンロードされました。
ブラウザーとリレー キャッシュ (CDN など) が 1 年の有効期限で CSS をキャッシュできるようにします。ファイル名にファイルのフィンガープリントを埋め込んでいるため、1 年間の「前方有効期限」を安全に使用できることに注意してください。CSS が更新されると、URL も変更されます。
JavaScript の有効期限も 1 年に設定されていますが、おそらく CDN がキャッシュすべきではないプライベート ユーザー データが含まれているため、プライベートとしてマークされています。
キャッシュされた画像の有効期限をできるだけ長く設定します。
上記の最初の項目で説明したフィンガープリント コードは、通常、ファイルの生成時に gulp や webpack などのパッケージ化ツールによって生成されるドキュメント コンテンツのハッシュ値を指します。その後、たとえば jquery.min.js とすると、ドキュメントに従って生成されたハッシュ値は 1iuiqe981823 となり、ファイル名は jquery.min.1iuiqe981823.js のように自動生成されます。これにより、変更がない場合でもドキュメントをキャッシュから確実に読み取れるだけでなく、変更があった場合でもドキュメントを適時に更新できるようになります。
この記事の大部分は、「HTTP Definitive Guide」を直接引用しています。最後の部分については、Google Developers ドキュメントを参照するのが最善の方法です。内容の一部は理解した上でのコード実装や検証です。
原文