HTTP DELETEリクエストを発行するとき、リクエストURIは削除するリソースを完全に識別するべきです。しかし、リクエストのエンティティボディの一部として追加のメタデータを追加することは許可されますか?
仕様 は明示的にそれを禁止したり推奨したりしないので、私はそれが許可されていると言う傾向があります。
Microsoftはそれを同じように見ている(私は聴衆の中でつぶやくのを聞くことができる)、彼らはADO.NET Data Services Frameworkの DELETEメソッドについてのMSDNの記事で述べる :
DELETEリクエストがエンティティボディを含む場合、ボディは無視されます[...]
さらにここに RFC2616 (HTTP 1.1)が要求に関して言わなければならないものがあります:
Content-Length
またはTransfer-Encoding
ヘッダーを含めることによって通知されます(セクション4.3)応答については、これが定義されています。
HTTP 1.1仕様( RFC 7231 )の最新の更新では、DELETE要求でエンティティ本体を明示的に許可しています。
DELETE要求メッセージ内のペイロードには定義された意味論がありません。 DELETE要求でペイロードボディを送信すると、既存の実装によっては要求が拒否される可能性があります。
TomcatとJettyのいくつかのバージョンは、存在してもエンティティ本体を無視するようです。あなたがそれを受け取るつもりなら、どれが厄介なことになるかもしれません。
削除要求で本体を使用する理由の1つは、楽観的同時実行制御です。
あなたはレコードのバージョン1を読みました。
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }
同僚がレコードのバージョン1を読みます。
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }
同僚がレコードを変更してデータベースを更新すると、バージョンが2に更新されます。
PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }
レコードを削除しようとしました。
DELETE /some-resource/1 { id:1, version:1 }
409 Conflict
楽観的ロック例外が発生するはずです。レコードをもう一度読み、重要であることを確認し、削除しないでください。
これを使用するもう1つの理由は、一度に複数のレコードを削除することです(たとえば、行選択チェックボックスを含むグリッド)。
DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content
各メッセージには独自のバージョンがあります。複数のヘッダーを使用して複数のバージョンを指定することもできますが、Georgeによると、これはより簡単ではるかに便利です。
これはTomcat(7.0.52)とSpring MVC(4.05)で、おそらく以前のバージョンでも動作します。
@RestController
public class TestController {
@RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
SomeBean echoDelete(@RequestBody SomeBean someBean) {
return someBean;
}
}
私には RFC 2616 はこれを指定していないようです。
セクション4.3から:
リクエスト内のメッセージボディの存在は、リクエストのメッセージヘッダにContent-LengthまたはTransfer-Encodingヘッダフィールドを含めることによって通知されます。要求メソッド(5.1.1節)の指定が要求中のエンティティボディの送信を許可していない場合、メッセージボディを要求に含めてはならない(MUST NOT)。サーバはどんなリクエストでもメッセージボディを読んで転送するべきです(SHOULD)。リクエストメソッドがentity-bodyに対して定義されたセマンティクスを含んでいない場合、リクエストを処理するときにメッセージボディSHOULDは無視されるべきです。
そしてセクション9.7:
DELETEメソッドは、オリジンサーバがRequest-URIによって識別されたリソースを削除することを要求します。このメソッドはOriginサーバ上での人間の介入(あるいは他の手段)によって上書きされるかもしれません。 Originサーバから返されたステータスコードがアクションが正常に完了したことを示していても、クライアントは操作が実行されたことを保証できません。しかしながら、応答が与えられた時にリソースを削除するかアクセスできない場所に移動させるつもりでない限り、サーバは成功を示すべきではありません(SHOULD NOT)。
応答がステータスを記述するエンティティを含む場合は200(OK)、アクションがまだ実行されていない場合は202(承認済み)、アクションが実行されたが応答が含まれていない場合は204(コンテンツなし)エンティティ。
リクエストがキャッシュを通過し、Request-URIが1つ以上の現在キャッシュされているエンティティを識別している場合、それらのエントリは古いものとして扱われるべきです(SHOULD)。このメソッドへの応答はキャッシュ可能ではありません。
そのため、明示的に許可または許可されていないため、途中でプロキシがメッセージ本文を削除する可能性があります(ただし、読み、転送する必要があります)。
あなたがあなたのDELETEリクエストでボディを供給し、そしてグーグルクラウドHTTPSロードバランサーを使用しているならば、頭を上げて、それはあなたのリクエストを400エラーで拒否します。私は頭を壁にぶつけていて、Googleは、何らかの理由で、ボディ付きのDELETEリクエストは不正なリクエストであると考えていることを知りました。
ElasticSearchはこれを使っているようです: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api
つまり、Nettyはこれをサポートしています。
コメントで述べたように、もうそうではないかもしれません
これは定義されていません 。
DELETE要求メッセージ内のペイロードには定義された意味論がありません。 DELETE要求でペイロードボディを送信すると、既存の実装によっては要求が拒否される可能性があります。
https://tools.ietf.org/html/rfc7231#page-29
誰かがこの問題のテストに遭遇した場合、いいえそれは普遍的にサポートされていません。
私は現在Sahi Proでテストしています、そしてそれはhttp DELETE呼び出しがどんな提供されたボディデータ(エンドポイントのデザインによって大量に削除するidの大きなリスト)をもぎ取ることは非常に明白です。
私は彼らと何度か連絡を取り合っているだけでなく、それらをレビューするためのスクリプト、画像、ログの3つの別々のパッケージで送られました、そして彼らはまだこれを確認していません。パッチが失敗し、会議が失敗したために後で彼らのサポートによって電話がかかってきましたが、私はまだしっかりした答えを得ていません。
私はSahiがこれをサポートしていないと確信しています、そして私は他の多くのツールがスイートに続くことを想像するでしょう。
これに対する良い答えが投稿されたとは思いませんが、既存の答えには素晴らしいコメントがたくさんあります。私はそれらのコメントの要旨を新しい答えに持ち上げます。
RFC7231からのこの段落 は数回引用されていますが、それを要約しています。
DELETE要求メッセージ内のペイロードには定義された意味論がありません。 DELETE要求でペイロードボディを送信すると、既存の実装によっては要求が拒否される可能性があります。
私が他の答えから逃したのは含意でした。はい、DELETE
リクエストにボディを含めることは許可されていますが、意味的には意味がありません。これが本当に意味することは、リクエストボディでDELETE
リクエストを発行することは、リクエストボディを含まないことと意味的に同等であるということです。
リクエストボディを含めてもリクエストには影響しませんので、それを含めても意味がありません。
tl; dr:技術的にはリクエストボディを持つDELETE
リクエストは許可されていますが、そうすることが役に立ちません。
リクエストボディでDELETEオペレーションを実装することができました。私はAWS LambdaとAWS APIゲートウェイを使い、Go言語を使いました。
Bodyと一緒にDELETEを使用するのは危険です... RESTよりもList Operationsのためにこのアプローチを好みます:
通常の運用
GET /objects/ すべてのオブジェクトを取得する
GET /object / _ id _ 指定したIDのObjectを取得する
POST /objects 新しいオブジェクトを追加します
PUT /object / _ id _ 指定されたIDを持つオブジェクトを追加し、オブジェクトを更新します
DELETE /object / _ id _ 指定したIDのオブジェクトを削除します
すべてのカスタムアクションはPOST
POST /objects / addList bodyに含まれるオブジェクトのリストまたは配列を追加します
POST /objects / deleteList bodyに含まれるオブジェクトのリストを削除する
POST /objects / customQuery 本体内のカスタムクエリに基づいてListを作成します
クライアントがあなたの拡張操作をサポートしていない場合、それらは通常の方法で動作することができます。