HTTPキャッシュにおける304 Not Modifiedレスポンスの理解

ウェブアプリケーションを開発する際、効率的なリソース管理はパフォーマンスにとって重要です。特にファイルアクセスやブラウザキャッシュに関しては、304 Not Modified HTTPレスポンスを正しく活用することが最適化の一つの方法です。このレスポンスは、ブラウザに対してリクエストされたリソースが前回取得されて以来変更されていないことを通知し、ブラウザは再度ダウンロードするのではなく、キャッシュされたバージョンを使用し続けることができます。しかし、いつこのレスポンスを送るべきかをどうやって判断すればよいのでしょうか?ステップ・バイ・ステップで分解していきましょう。

チェックすべき主要なHTTPヘッダー

304 Not Modifiedレスポンスを送信するべきかどうかを判断するには、クライアントのブラウザから送信された特定のHTTPヘッダーを確認する必要があります。主に注目すべきヘッダーは以下の2つです。

  1. Etag: このヘッダーは、特定のバージョンのリソースに対するユニークな識別子として機能します。ブラウザは、キャッシュされたEtagとサーバーのEtagを比較して、一致するかを確認します。
  2. If-None-Match: このヘッダーはブラウザによって送信され、キャッシュされたEtag値を含んでいます。リソースが変更されていない場合、サーバーは304と応答できます。

何を探すべきか

  • ブラウザからのEtagが存在するか: ブラウザがリクエストにEtagまたはIf-None-Matchヘッダーのどちらかを含めている場合、それはリソースの以前のキャッシュバージョンを持っていることを示します。
  • 引用に関する注意: ブラウザは時折Etag値を引用符で囲むことがあります。比較の前にこれらの引用符を取り除くことを確認してください。

初回レスポンスに必要なヘッダー

リソースを初めて送信する際(通常、200 OKレスポンス),リソースの状態に関する情報をブラウザに提供する適切なヘッダーを含めることが重要です。

  • Last-Modified: リソースが最後に変更された時刻を示します。これは、Etagと並んでキャッシュバリデーションの代替チェックとなることがあります。
  • Etag(前述の通り): これはリソースのために生成され、将来のキャッシュバリデーションを容易にするためにレスポンスヘッダーに含めるべきです。

ロジックの実装

以下は、304 Not Modifiedレスポンスを送信するロジックを実装するための簡略化された擬似コードの例です。

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

サーバーロジックの例

これをサーバーロジックで実装する方法は以下の通りです。

/* クライアントはEtagまたはIf-None-Matchのどちらかを設定する必要があります */
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;
}   

apr_table_add(r->headers_out, "ETag", etag);

if (etagin != NULL && strcmp(etagin, etag) == 0) {
    /* Etagが一致する場合、304ステータスを返す */
    rc = HTTP_NOT_MODIFIED;
}

最後の考え

304 Not Modifiedレスポンスをいつ、どのように送信するかを知っておくことで、サーバーの負荷を効果的に削減し、ユーザー体験を向上させることができます。初回レスポンス時にEtagLast-Modifiedヘッダーを含めることが重要であることも忘れないでください。これにより、クライアントがその後正確なキャッシュバリデーションリクエストを行えるようになります。Etagの生成について質問がある場合や、さらなる実装支援が必要であれば、ぜひ詳細な例を求めて連絡してください。コーディングを楽しんでください!