web-dev-qa-db-ja.com

エンティティ本体はHTTP DELETE要求を許可されていますか?

HTTP DELETEリクエストを発行するとき、リクエストURIは削除するリソースを完全に識別するべきです。しかし、リクエストのエンティティボディの一部として追加のメタデータを追加することは許可されますか?

591
Haacked

仕様 は明示的にそれを禁止したり推奨したりしないので、私はそれが許可されていると言う傾向があります。

Microsoftはそれを同じように見ている(私は聴衆の中でつぶやくのを聞くことができる)、彼らはADO.NET Data Services Frameworkの DELETEメソッドについてのMSDNの記事で述べる

DELETEリクエストがエンティティボディを含む場合、ボディは無視されます[...]

さらにここに RFC2616 (HTTP 1.1)が要求に関して言わなければならないものがあります:

  • entity-body は、 message-body が存在する場合にのみ存在します(セクション7.2)。
  • message-body の存在は、Content-LengthまたはTransfer-Encodingヘッダーを含めることによって通知されます(セクション4.3)
  • リクエストメソッドの指定で entity-body の送信が許可されていない場合は、 message-body を含めないでください(セクション4.3)。
  • entity-body は、TRACEリクエストでのみ明示的に禁止されています。他のすべてのリクエストタイプは制限されていません(特にセクション9、9.8)。

応答については、これが定義されています。

  • message-body が含まれるかどうかは、リクエストメソッドレスポンスステータスの両方に依存します(セクション4.3)。
  • a message-body はHEADリクエストへの応答では明示的に禁止されています(特にセクション9、9.4)。
  • a message-body は、1xx(情報)、204(内容なし)、および304(未修正)の応答では明示的に禁止されています(セクション4.3)。
  • それ以外のすべての応答にはメッセージ本体が含まれます。ただし、メッセージ本体の長さはゼロでもかまいません(セクション4.3)。
486
Tomalak

HTTP 1.1仕様( RFC 7231 )の最新の更新では、DELETE要求でエンティティ本体を明示的に許可しています。

DELETE要求メッセージ内のペイロードには定義された意味論がありません。 DELETE要求でペイロードボディを送信すると、既存の実装によっては要求が拒否される可能性があります。

143
grzes

TomcatとJettyのいくつかのバージョンは、存在してもエンティティ本体を無視するようです。あなたがそれを受け取るつもりなら、どれが厄介なことになるかもしれません。

52
evan.leonard

削除要求で本体を使用する理由の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;
    }
}
44
Neil McGuigan

私には 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)。このメソッドへの応答はキャッシュ可能ではありません。

そのため、明示的に許可または許可されていないため、途中でプロキシがメッセージ本文を削除する可能性があります(ただし、読み、転送する必要があります)。

27
Adam Rosenfield

あなたがあなたのDELETEリクエストでボディを供給し、そしてグーグルクラウドHTTPSロードバランサーを使用しているならば、頭を上げて、それはあなたのリクエストを400エラーで拒否します。私は頭を壁にぶつけていて、Googleは、何らかの理由で、ボディ付きのDELETEリクエストは不正なリクエストであると考えていることを知りました。

15
Ben Fried

ElasticSearchはこれを使っているようです: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

つまり、Nettyはこれをサポートしています。

コメントで述べたように、もうそうではないかもしれません

7

これは定義されていません

DELETE要求メッセージ内のペイロードには定義された意味論がありません。 DELETE要求でペイロードボディを送信すると、既存の実装によっては要求が拒否される可能性があります。
https://tools.ietf.org/html/rfc7231#page-29

6
Simon Jin

バージョン3.0のOpenAPI仕様では、ボディを含むDELETEメソッドのサポートが廃止されたことは注目に値します。

参照については、 here および here を参照してください。

これは、将来の実装、ドキュメント、またはこれらのAPIの使用に影響を与える可能性があります。

5
Clever Human

誰かがこの問題のテストに遭遇した場合、いいえそれは普遍的にサポートされていません。

私は現在Sahi Proでテストしています、そしてそれはhttp DELETE呼び出しがどんな提供されたボディデータ(エンドポイントのデザインによって大量に削除するidの大きなリスト)をもぎ取ることは非常に明白です。

私は彼らと何度か連絡を取り合っているだけでなく、それらをレビューするためのスクリプト、画像、ログの3つの別々のパッケージで送られました、そして彼らはまだこれを確認していません。パッチが失敗し、会議が失敗したために後で彼らのサポートによって電話がかかってきましたが、私はまだしっかりした答えを得ていません。

私はSahiがこれをサポートしていないと確信しています、そして私は他の多くのツールがスイートに続くことを想像するでしょう。

3
parker

これに対する良い答えが投稿されたとは思いませんが、既存の答えには素晴らしいコメントがたくさんあります。私はそれらのコメントの要旨を新しい答えに持ち上げます。

RFC7231からのこの段落 は数回引用されていますが、それを要約しています。

DELETE要求メッセージ内のペイロードには定義された意味論がありません。 DELETE要求でペイロードボディを送信すると、既存の実装によっては要求が拒否される可能性があります。

私が他の答えから逃したのは含意でした。はい、DELETEリクエストにボディを含めることは許可されていますが、意味的には意味がありません。これが本当に意味することは、リクエストボディでDELETEリクエストを発行することは、リクエストボディを含まないことと意味的に同等であるということです。

リクエストボディを含めてもリクエストには影響しませんので、それを含めても意味がありません。

tl; dr:技術的にはリクエストボディを持つDELETEリクエストは許可されていますが、そうすることが役に立ちません。

2
Evert

リクエストボディでDELETEオペレーションを実装することができました。私はAWS LambdaとAWS APIゲートウェイを使い、Go言語を使いました。

1
Dattatray

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を作成します

クライアントがあなたの拡張操作をサポートしていない場合、それらは通常の方法で動作することができます。

0
Eliezer Garza