[18] [DFN[[CODE(HTTP)[[[304]]]]]] ([DFN[[[Not Modified]]]]) は、
[CODE(HTTP)@en[[[If-Modified-Since:]]]] [[ヘッダー]]で指定された時刻より後に[[対象資源]]が変更されていないことを示す[[状態符号]]です。

* 仕様書

[REFS[
- [7] '''[CITE@en[RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests]] ([TIME[2014-09-11 10:02:44 +09:00]] 版) <https://tools.ietf.org/html/rfc7232#section-4.1>'''
- [305] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-3.3>
- [3] [CITE@en[RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests]] ([TIME[2014-09-11 10:02:44 +09:00]] 版) <https://tools.ietf.org/html/rfc7232#section-3.2>
- [6] [CITE@en[RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests]] ([TIME[2014-09-11 10:02:44 +09:00]] 版) <https://tools.ietf.org/html/rfc7232#section-3.3>
- [15] [CITE@en[RFC 2295 - Transparent Content Negotiation in HTTP]] ([TIME[2014-08-31 19:36:42 +09:00]] 版) <http://tools.ietf.org/html/rfc2295#section-8.5>
]REFS]

* 意味

[8] [CODE(HTTP)[[[304]]]] は、[[条件付き要求]]である [CODE(HTTP)@en[[[GET]]]] や
[CODE(HTTP)@en[[[HEAD]]]] の[[要求]]を受信した際に、条件が[[偽]]でなかったなら
[CODE(HTTP)[[[200]]]] [[応答]]を送信していたであろうことを示す[[状態符号]]です [SRC[>>7]]。

[9] これはすなわち、[[クライアント]]が既に[[対象資源]]の[[妥当]]な[[表現]]を持っているため、
再度あえて転送する必要はなく、従って[[クライアント]]が保持している[[表現]]が
[CODE(HTTP)[[[200]]]] [[応答]]の [[payload]] だったかのように[[リダイレクト]]するものです。
[SRC[>>7]]

;; [10] これは一般的な意味の [[HTTPリダイレクト]]とは異なりますが、
[[HTTP]] 仕様上は[[クライアント]]の保持する[[キャッシュ]]への
「[[リダイレクト]]」に分類されています。

* 構文

[11] [CODE(HTTP)[[[304]]]] [[応答]]を[[生成]]する[[鯖]]は、
[CODE(HTTP)[[[200]]]] [[応答]]だったなら送られるであろう次の[[ヘッダー]]を同様に[[生成]]しなければ[['''なりません''']]
[SRC[>>7]]。
[FIG(short list)[
- [CODE(HTTP)@en[[[Cache-Control:]]]]
- [CODE(HTTP)@en[[[Content-Location:]]]]
- [CODE(HTTP)@en[[[Date:]]]]
- [CODE(HTTP)@en[[[ETag:]]]]
- [CODE(HTTP)@en[[[Expires:]]]]
- [CODE(HTTP)@en[[[Vary:]]]]
]FIG]

;; [17] [CODE(HTTP)[[[200]]]] の時送らないものは、送る必要はありません。

;; [22] [CODE(HTTP)[[[206]]]] でも同様の規定があります。

[12] [[送信者]]は、 >>11 以外の[[表現メタデータ]]は[[キャッシュ]]の更新の案内のためのものを除き、
[[生成]]する[['''べきではありません''']] [SRC[>>7]]。

[EG[
[13] 例えば [CODE(HTTP)@en[[[Last-Modified:]]]] は [CODE(HTTP)@en[[[ETag:]]]]
がない場合に有用かもしれません [SRC[>>7]]。
]EG]

;; [14] ... というような曖昧な規定よりも、適切なもの、不適切なもののリストを仕様書に含めていただけるた方が有用だと思うのですが...
他に該当しそうなものは [CODE(HTTP)@en[[[Pragma:]]]] でしょうか。

;; [19] [CODE(HTTP)@en[[[If-Modified-Since:]]]] に対する[[応答]]として [CODE(HTTP)[[[304]]]]
を返す場合について、以前に[[キャッシュ]]された[[応答]]を識別したり、
更新したりするのに有用な[[メタデータ]]のみを含める[['''べき''']] [SRC[>>6]]
との規定がありますが、これら[[ヘッダー]]に関する規定をより曖昧に言い直しただけに過ぎないと推測されます。
(なぜわざわざ曖昧に繰り返す必要があるのか謎ですが、[[RFC]] としては一般的な品質なので、
一々気にするだけ無駄でしょう。)

[16] [CODE(HTTP)@en[[[TCN:]]]] は[[透過的折衝可能資源]]の [CODE(HTTP)[[[304]]]]
[[応答]]に含めても構いません [SRC[>>15]]。

[20] これらの[[ヘッダー]]についての情報は、 >>21 の [[JSON]]
ファイルの [CODE[304_representation_metadata]] に含まれています。
[REFS[
- [21] [CITE@en[data-web-defs/headers.txt at master · manakai/data-web-defs]] ([TIME[2014-09-15 14:34:53 +09:00]] 版) <https://github.com/manakai/data-web-defs/blob/master/doc/headers.txt>
]REFS]

[306] [CODE(HTTP)[[[304]]]] [[応答]]は、[[メッセージ本体]]を持ちません [SRC[>>305, >>7]]。

* 文脈

[4] [CODE(HTTP)@en[[[If-None-Match:]]]] の条件を満たさない場合で[[要求メソッド]]が
[CODE(HTTP)@en[[[GET]]]] か [CODE(HTTP)@en[[[HEAD]]]] の場合には、
[CODE(HTTP)[[[304]]]] [[応答]]を返すことができます [SRC[>>3]]。

[5] [CODE(HTTP)@en[[[If-Modified-Since:]]]] の条件を満たさない場合には、
[CODE(HTTP)[[[304]]]] [[応答]]を返すことができます [SRC[>>6]]。

* 処理モデル

[23] [[キャッシュ]]の更新処理については、[[条件付き要求]]を参照。

* 歴史

[FIG(quote)[
[FIGCAPTION[
[307] RFC 1945 (HTTP/1.0); RFC 2068・2616 (HTTP/1.1) 10.3.5 304 Not Modified
]FIGCAPTION]

> If the client has performed a conditional GET request and access is
allowed, but the document has not been modified [DEL[[DEL[{1945}]] since the date and time specified in the If-Modified-Since field]],
the server [DEL[[DEL[{1945}]] must]] [INS[[DEL[{2068}]] SHOULD]] respond with this status code [DEL[[DEL[{1945}]] and not send an Entity-Body to the client]]. [INS[[DEL[{2068,2616}]] The [INS[304]] response MUST NOT contain a message-body[INS[, [INS[{2616}]] and thus is always terminated by the first empty line after the header fields]].]] [DEL[[DEL[{1945}]] Header fields contained in the response should only include information which is relevant to cache managers or which may have changed independently of the entity's Last-Modified date. Examples of relevant header fields include: Date, Server, and Expires. A cache should update its cached entity to reflect any new field values given in the 304 response.]]

クライアントが条件付き [CODE(HTTP)[[[GET]]]] 要求を行い、接続は認められたものの、
文書は[DEL[[CODE(HTTP)[[[If-Modified-Since]]]] 欄に指定されて日付・時刻から]]修正されていないなら、
サーバーはこの状態符号で応答[DEL[してはならず、クライアントに [CODE(ABNF)[[[Entity-Body]]]] を送信してはなりません。]][INS[する'''べき'''です。]][INS[[CODE(HTTP)[304]] 応答は [CODE(ABNF)[[[message-body]]]] を含んでいては'''ならりません'''[INS[で、従って頭欄の後の最初の空行で常に終端します]]。]][DEL[応答中に含まれる頭欄はキャッシュ管理器に関係する情報又は実体の [CODE(HTTP)[[[Last-Modified]]]] 日付に独立して変わったかもしれない情報のみを含むべきです。関係する頭欄の例 : [CODE(HTTP)[[[Date]]]], [CODE(HTTP)[[[Server]]]], [CODE(HTTP)[[[Expires]]]]。キャッシュは、キャッシュした実体が [CODE(HTTP)[304]] 応答で与えられた新しい欄値を反映するように更新するべきです。]]

[INS[

> [INS[{2068,2616}]]  The response MUST include the following header fields:
- Date[INS[, unless its omission is required by section 14.18.1]]

応答は次の頭欄を含まなければ'''なりません''':
- [CODE(HTTP)[Date]] [INS[省略が義務付けられている場合を除く]]

[INS[

> [INS[{2616}]] If a clockless origin server obeys these rules, and proxies and
clients add their own Date to any response received without one (as
already specified by [RFC 2068], section 14.19), caches will operate correctly.

時計のない起源サーバーはこれらの規則に従い、
串及びクライアントが自身の [CODE(HTTP)[Date]] を [CODE(HTTP)[Date]]
なしで受信した応答に付け加えれば、
キャッシュは正しく処理されます。
]INS]

>
- ETag and/or Content-Location, if the header would have been sent in
a 200 response to the same request
- Expires, Cache-Control, and/or Vary, if the field-value might
differ from that sent in any previous response for the same variant

- [CODE(HTTP)[ETag]] [[及び/又は]] [CODE(HTTP)[[[Content-Location]]]]
その頭が同じ要求に対する [CODE(HTTP)[[[200]]]] 応答でも送られるであろうなら
- [CODE(HTTP)[[[Expires]]]], [CODE(HTTP)[[[Cache-Control]]]]
及び/又は [CODE(HTTP)[[[Vary]]]] 
欄値が同じ変種に対する以前の応答で送られたものと異なるかもしれないなら

> If the conditional GET used a strong cache validator (see section
13.3.3), the response SHOULD NOT include other entity-headers.
Otherwise (i.e., the conditional GET used a weak validator), the
response MUST NOT include other entity-headers; this prevents
inconsistencies between cached entity-bodies and updated headers.

条件付き [CODE(HTTP)[GET]] が[[強いキャッシュ検証]]を使っているなら、
応答は他の実体頭欄を含む'''べきではありません'''。
そうでなければ、 (つまり条件付き [CODE(HTTP)[GET]] が弱い検証を使っているなら、)
応答は他の実体頭欄を含んでは'''なりません'''。
これによってキャッシュされている実体本体と更新された頭の不一致を防ぐことができます。

> If a 304 response indicates an entity not currently cached, then the
cache MUST disregard the response and repeat the request without the conditional.

[CODE(HTTP)[304]] 応答が実体は現在キャッシュされていないことを示すなら、
その時はキャッシュは応答を捨てて条件付きでない要求を繰り返さなければ'''なりません'''。

> If a cache uses a received 304 response to update a cache entry, the
cache MUST update the entry to reflect any new field values given in the response.

キャッシュが受信した [CODE(HTTP)[304]] 応答を使ってキャッシュ項目を更新するなら、
キャッシュは応答中に与えられた新しい欄値を反映して実体を更新しなければ'''なりません'''。

[DEL[

> [INS[{2068}]] The 304 response MUST NOT include a message-body, and thus is always
terminated by the first empty line after the header fields.

[CODE(HTTP)[304]] 応答は [CODE(ABNF)[[[message-body]]]] を含んでは'''ならず'''、
従って常に頭欄の後の最小の空行で終端します。
]DEL]
]INS]
]FIG]

* メモ

[1] この応答符号、明らかに意味が他の [CODE(HTTP)[[[3xx]]]] 
と違いますよねえ。。。

[2]
[CODE(DOMi)@en[[[XMLHttpRequest]]]]で[CODE(DOMa)@en[[[statusCode]]]]が[CODE(HTTP)@en[[[304]]]]になることがよくありますが、それを考慮していない使用例が多過ぎのような気がします。。。
([[名無しさん]] [sage] [WEAK[2006-01-01 05:59:22 +00:00]])

[24] [CITE@en[Close #141: fix 304 handling · whatwg/fetch@1a2f6b4]]
([TIME[2015-11-01 19:39:10 +09:00]] 版)
<https://github.com/whatwg/fetch/commit/1a2f6b49d616cfd74536c1a8dbed8b5c1215d548>