HTTPQUERY
日本語

304 Not Modified

使い方

304 Not Modified ステータスコードは、GET や HEAD のようにリクエストが安全であり、クライアントのキャッシュに保存されているバージョン以降にリソースが変更されていないとサーバーが判断した場合に送信されます。クライアントがすでに保持しているデータをサーバーが再送信しないため、帯域が節約されます。

注意

304 Not Modified は 3xx のステータスクラスを共有していますが、リダイレクトではありません。リダイレクト(301、302、307、308)は Location ヘッダーを通じてクライアントを別の URL へ送ります。304 は同じリソースのキャッシュ済みコピーを再利用するようクライアントに伝えるものであり、Location ヘッダーは送信されません。ブラウザの DevTools が 304 をリダイレクトと同じ分類にまとめることがあり、それが混乱に拍車をかけています。

注意

DevTools の「200 (from disk cache)」は、Cache-Control の max-age が期限切れになっていないため、ブラウザがサーバーに問い合わせずキャッシュからリソースを提供したことを意味します。304 は、ブラウザがサーバーに問い合わせて再検証し、サーバーがキャッシュ済みのコピーは最新だと確認したことを意味します。キャッシュされた 200 はネットワークリクエストをまったく伴いませんが、304 は1往復を伴います。

サーバーはレスポンスで以下のヘッダーのうち1つ以上を生成します。

304 Not Modified レスポンスの目的は帯域を最小化することであるため、サーバーはキャッシュ更新の処理に役立つ場合を除き、元のリクエストに含まれていなかったヘッダーを省略します。

条件付き GET リクエストでは、関連するディレクティブは If-None-Match と If-Modified-Since です。これらは、リソースを再送信する必要があるかどうかを評価するために ETag などのバリデーターに依存します。

例

クライアントがリソースを要求し、そのバージョンを識別する ETag を受け取り、その後に再検証します。サーバーはリソースが変更されていないことを認識し、304 Not Modified を返します。3回目のリクエストでは新しいバージョンが利用可能であり、更新された ETag とともに完全な 200 レスポンスが送信されます。

注意

サーバーがリソースを更新するたびに、新しい ETag が生成されます。あるいは、サーバーが Last-Modified の日付を返し、クライアントが代わりに If-Modified-Since を使うことで、サーバーが ETag の履歴を保持する必要がなくなります。

SEO への影響

Googlebot が 304 を受け取ると、クローラーは前回のクロール以降コンテンツが変更されていないと認識します。インデックス登録パイプラインはその URL のランキングシグナルを再計算しますが、コンテンツの再取得や再インデックスは行いません。

古い 304 の落とし穴

304 は、キャッシュされたバージョンがまだ最新であることを確認するものです。サーバーが以前に壊れたページ(空のボディやエラーコンテンツ)を 200 で提供し、クローラーがその結果をキャッシュしていた場合、その後の 304 はクローラーに壊れたバージョンが維持されていると伝えます。「コンテンツ」が変更されていないため、クローラーは再確認をやめてしまいます。ページを修正するだけでは不十分です。サーバーは、キャッシュされたエラーを置き換えるために、修正済みのボディ(と新しい ETag)を伴う新鮮な 200 を返さなければなりません。根本原因(過去の一時的なエラー)がもはや見えないため、このシナリオのデバッグは困難です。

最初のリクエスト

GET /news.html HTTP/1.1
Host: example.com

最初のレスポンス

HTTP/1.1 200 OK
ETag: "1234000"
Content-Type: text/html
Content-Length: 1250

<message body contains requested resource>

2回目のリクエスト

GET /news.html HTTP/1.1
Host: example.com
If-None-Match: "1234000"

2回目のレスポンス

HTTP/1.1 304 Not Modified
ETag: "1234000"

3回目のリクエスト

GET /news.html HTTP/1.1
Host: example.com
If-None-Match: "1234000"

3回目のレスポンス

HTTP/1.1 200 OK
ETag: "1234001"
Content-Type: text/html
Content-Length: 1600

<message body contains requested resource>

コードリファレンス

.NET

HttpStatusCode.NotModified

Rust

http::StatusCode::NOT_MODIFIED

Rails

:not_modified

Go

http.StatusNotModified

Symfony

Response::HTTP_NOT_MODIFIED

Python3.5+

http.HTTPStatus.NOT_MODIFIED

Java

java.net.HttpURLConnection.HTTP_NOT_MODIFIED

Apache HttpComponents Core

org.apache.hc.core5.http.HttpStatus.SC_NOT_MODIFIED

Angular

@angular/common/http/HttpStatusCode.NotModified