@ResponseStatusで、ステータスコード204(`NO_CONTENT`)を指定するとレスポンスボディが空になる->204の場合はボディは空にすべき
元々以下のようなdeleteメソッドを実装していた。
@DeleteMapping("/{id}")
public DTO delete(@PathVariable("id") Long id) {
return DTO.of(Service.delete(id));
}
このメソッドの役目は、指定されたIDのデータを物理削除して、削除に成功したデータの内容を返すこと。
レスポンスステータスコードは200が返される。
しかし、ステータスコードを204にすることになったので、以下のように記述を修正。
期待する動作は、
- レスポンスステータスコードが204
- レスポンスボディに削除に成功したデータが格納されている
@DeleteMapping("/{id}")
@ResponseStatus(code = HttpStatus.NO_CONTENT)
public DTO delete(@PathVariable("id") Long id) {
return DTO.of(Service.delete(id));
}
この状態で試しに処理を実行したところ、
ステータスコードは204になったが、削除に成功したデータが格納されなくなってしまった。
色々調べてみたところ、「204を返すときは、レスポンスボディは空であるべき」 ということだった。
成功したレスポンスは、もしレスポンスがステータスで表しているエンティティを含んでいるなら 200 (OK)、もし動作がまだ行われていないなら 202 (Accepted)、もし動作は行われたが、レスポンスにエンティティを含んでいないなら 204 (No Content) であるべきである。
DELETE メソッドが成功裡に適用された場合、 生成元サーバは、 動作状況に応じて,次のいずれかの状態°コードを送信するべきである:
動作は成功する見込みが高いが、 まだ実行済みでない場合 :202 (Accepted)
動作は実行済みで、 更なる情報は給されない場合 :204 (No Content)
動作は実行済みで、 応答メッセージが[ その状態°を述べる表現 ]を内包する場合 :200 (OK)
そして今回の現象は、おそらくSpringBootがこの内容に従ってよしなにしてくれているものと思われる(要検証)
今回はレスポンスで204が返されることが指定されているため、戻り値を削除した上で、対応する。
RFCの仕様を見てみる(RFC7231)
(原文)
A 204 response is terminated by the first empty line after the header fields because it cannot contain a message body.
(DeepL)
204応答は、メッセージボディを含むことができないので、ヘッダーフィールド の後の最初の空行で終了する。
仕様によれば、「含むことができない(it cannot contain...
)」とされている。
なので204のボディは空にすべき、という仕様になっている模様。
↑で貼り付けたRFC7231は既に廃止済みでRFC9110になっていた。
(原文)
A 204 response is terminated by the end of the header section; it cannot contain content or trailers.
(DeepL)
204応答はヘッダーセクションの終わりで終了する;コンテンツやトレーラーは含まれない。
内容はほぼ一緒。意味合いは同じと思われる。
RFC9110でこれまでボディ
と呼んでいたものが、コンテンツ
と呼称されるようになった模様。
RFC9110について補足
@ResponseStatus