304 Not Modified 応答を送信するタイミングを知る方法
-
08-06-2019 - |
質問
さまざまなファイルへのアクセスを制御するリソース処理メソッドを作成しているのですが、ブラウザのキャッシュを利用できるようにしたいと考えています。私の質問は 2 つあります。
304 応答を送信する必要があるかどうかを確実に知るために確認する必要がある、最終的な HTTP ヘッダーはどれですか。また、それらを確認するときに何を探す必要がありますか?
さらに、最初にファイル (「Last-Modified」など) を 200 応答として送信するときに送信する必要があるヘッダーはありますか?
いくつかの疑似コードがおそらく最も役立つ答えになるでしょう。
キャッシュ制御ヘッダーについてはどうですか?考えられるさまざまな値は、クライアントに送信するもの (つまり max-age) に影響を与えることができますか、それとも if-modified-since のみに従う必要がありますか?
解決
これが私がそれを実装した方法です。このコードは 1 年以上前から複数のブラウザで動作しており、かなり信頼できると思います。これはに基づいています RFC 2616 そして、さまざまなブラウザがいつ何を送信したかを観察することによって。
疑似コードは次のとおりです。
server_etag = gen_etag_for_this_file(myfile) etag_from_browser = get_header("Etag") if etag_from_browser does not exist: etag_from_browser = get_header("If-None-Match") if the browser has quoted the etag: strip the quotes (e.g. "foo" --> foo) set server_etag into http header if etag_from_browser matches server_etag send 304 return code to browser
これを処理するサーバー ロジックのスニペットを次に示します。
/* the client should set either Etag or If-None-Match */ /* some clients quote the parm, strip quotes if so */ mketag(etag, &sb); etagin = apr_table_get(r->headers_in, "Etag"); if (etagin == NULL) etagin = apr_table_get(r->headers_in, "If-None-Match"); if (etag != NULL && etag[0] == '"') { int sl; sl = strlen(etag); memmove(etag, etag+1, sl+1); etag[sl-2] = 0; logit(2,"etag=:%s:",etag); } ... apr_table_add(r->headers_out, "ETag", etag); ... if (etagin != NULL && strcmp(etagin, etag) == 0) { /* if the etag matches, we return a 304 */ rc = HTTP_NOT_MODIFIED; }
etag の生成に関するヘルプが必要な場合は、別の質問を投稿してください。同様にそれを行うコードをいくつか掘り出します。ひーっ!
他のヒント
304 Not Modified 応答は、If-Modified-Since (「IMS」) ヘッダーまたは If-Not-Match (「INM」) ヘッダーを含む GET または HEAD リクエストの結果として発生する可能性があります。
これらのヘッダーを受け取ったときにどうするかを決定するには、これらの条件付きヘッダーなしで GET リクエストを処理していると想像してください。その応答内の ETag ヘッダーと Last-Modified ヘッダーの値が何であるかを判断し、それらを使用して決定を行います。これを決定する方が完全な応答を構築するよりもコストがかからないようにシステムを構築できていれば幸いです。
INM があり、そのヘッダーの値が ETag に配置する値と同じである場合は、304 で応答します。
IMS があり、そのヘッダーの日付値が Last-Modified に配置する日付値よりも後の場合は、304 で応答します。
それ以外の場合は、リクエストにこれらのヘッダーが含まれていないものとして処理を進めます。
質問のパート 2 に対する最小限の労力でアプローチするには、Web アプリケーションで簡単かつ正確に生成できるヘッダー (Expires、ETag、および Last-Modified) を見つけてください。
推奨される読み物については、次のとおりです。
クライアントがすでにキャッシュにページがある可能性があることを明示的に示している場合は、304 を送信する必要があります。これは条件付き GET と呼ばれ、以下を含める必要があります。 変更された場合-以降 リクエストのヘッダー。
基本的に、このリクエスト ヘッダーには、クライアントがキャッシュされたコピーを所有していると主張する日付が含まれています。この日付以降にコンテンツが変更されたかどうかを確認し、変更されていない場合は 304 を送信する必要があります。
見る http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 RFC の関連セクションを参照してください。
キャッシュされているが安全なリソースも処理します。ETAg ヘッダー (RFC 2616 セクション 13.3 で推奨されている [SHOULD]) を送信または生成する場合、クライアントはそれを条件付きリクエスト (通常は If-None-Match - HTTP_IF_NONE_MATCH - ヘッダー) で使用しなければなりません (MUST)。Last-Modified ヘッダーを送信する場合は (これも行う必要があります)、If-Modified-Since - HTTP_IF_MODIFIED_SINCE - ヘッダーを確認する必要があります。両方を送信する場合、クライアントは両方を送信する必要がありますが、ETag を送信しなければなりません。また、検証は、条件付きヘッダーが送信するヘッダーと厳密に等しいかどうかをチェックすることとして定義されているだけであることに注意してください。また、範囲リクエスト (リソースの一部のみがリクエストされる場合) には、強力なバリデータ (ETag など) のみが使用されます。
実際には、保護しているリソースはかなり静的であり、1 秒の遅延時間は許容できるため、次のことを行っています。
ユーザーが要求されたリソースへのアクセスを許可されているかどうかを確認する
そうでない場合は、必要に応じてリダイレクトするか、4xx 応答を送信します。ハッキングの試みまたはセキュリティのエンドランを実行する露骨な試みのように見えるリクエストに対して 404 レスポンスを生成します。
If-Modified-Since ヘッダーを、送信する Last-Modified ヘッダー (以下を参照) と厳密に同等であるかどうか比較します。
一致する場合は、304 Not Modified 応答を送信し、ページ処理を終了します。
リクエストされたリソースの変更時刻を使用して Last-Modified ヘッダーを作成する
RFC 2616 で HTTP 日付形式を調べてください。
ヘッダーとリソースのコンテンツを適切な Content-Type とともに送信します。
私たちの目的には過剰であるため、ETag ヘッダーを避けることにしました。日付時刻スタンプを ETag として使用することもできると思います。真の ETag システムに移行する場合は、おそらくリソースの計算されたハッシュを保存し、それらを ETag として使用することになるでしょう。
リソースがデータベースのコンテンツなどから動的に生成される場合、ETag は必要に応じて入力される単なるテキストであるため、ニーズに適している可能性があります。
キャッシュ制御に関して:
キャッシュ制御を適切な値に設定すること以外は、サービスを提供するときにキャッシュ制御について心配する必要はありません。これは基本的に、ブラウザおよび他のダウンストリーム エンティティ (プロキシなど) に、キャッシュがタイムアウトになるまでに経過する必要がある最大時間を通知します。