エンティティボディはHTTP DELETEリクエストで許可されていますか?


717

HTTP DELETE要求を発行する場合、要求URIは削除するリソースを完全に識別する必要があります。ただし、リクエストのエンティティボディの一部として追加のメタデータを追加することはできますか?


4
ASP.NET WebApi 2では、HttpDeleteエンドポイントのFromBodyパラメーターは無視されます。
ジェニー・オライリー

2
同様の懸念がありますが、私の場合は異なります。100個のオブジェクトを削除したいときに、一括削除リクエストを発行したい。確かに、これはHTTP 2.0より前のネットワークのパフォーマンスを大幅に向上させます。
Singagirl 2016

1
HTTP / 2に変更はありますか?
ジョットマンシン2017

回答:


570

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

マイクロソフトはそれを同じように見ています(聴衆の中でつぶやくのを聞くことができます)、彼らはADO.NETデータサービスフレームワークのDELETEメソッドに関するMSDNの記事で述べています

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

さらに、RFC2616(HTTP 1.1)が要求に関して述べなければならないことは次のとおりです。

  • エンティティボディは、場合にのみ存在しているメッセージ本体が存在する(セクション7.2)
  • メッセージ本文の存在は、Content-LengthまたはTransfer-Encodingヘッダーを含めることで通知されます(セクション4.3)
  • リクエストメソッドの指定でエンティティボディの送信が許可されていない場合は、メッセージボディを含めることはできません(セクション4.3)
  • エンティティボディは、明示的トレースに禁止されているのみで、他のすべての要求タイプが(セクション9、および9.8具体的に)無制限される要求

応答の場合、これは定義されています:

  • メッセージ本文が含まれるかどうかは、要求メソッド応答ステータスの両方に依存します(セクション4.3)
  • HEADリクエストへの応答では、メッセージ本文は明示的に禁止されています(特にセクション9、および9.4)
  • メッセージ本体は明示の1xx(情報)、204(コンテンツなし)に禁止、及び304(変更されていない)応答(セクション4.3)されています
  • 他のすべての応答にはメッセージ本文が含まれますが、長さがゼロの場合もあります(セクション4.3)

7
@ジェイソン間違いなく。カスタムヘッダーを使用して追加のデータを渡すこともできますが、リクエストボディを使用しないでください。
Tomalak 2012年

86
仕様ではDELETEリクエストにメッセージ本文を含めることを禁止していませんが、セクション4.3では、DELETEエンティティ本体に「定義されたセマンティクス」がないため、本文をサーバーで無視する必要があることを示しているようです。「サーバーは、任意のリクエストのメッセージボディ。リクエストメソッドにエンティティボディの定義されたセマンティクスが含まれていない場合、リクエストを処理するときにメッセージボディを無視する必要があります
シェリー2013年

72
多くのクライアントも、ボディ付きのDELETEを送信できないことに注意してください。これはちょうどAndroidで私を燃やしました。
Karmic Coder 2014

1
@KarmicCoder:すばらしい点。詳細:AndroidでのHTTP DELETEリクエストの送信
MS Dousti 2015年

2
HTTP仕様と混合した実装に関する多くの議論。クライアントは、仕様を解釈する方法で物事を実装します。これを仕様の意味と混同しないでください。実際のところ、仕様があいまいなままです。entity-bodyには意味が定義されていないため、無視する必要があるという意味があるという解釈には同意しません。人々は、存在するクライアント固有の解釈(ジャージー、Androidテストクライアントなど)から逆方向に作業し、仕様に忠実であるようにするのではなく、解釈を正当化しようとしていると思います。人間は間違いやすいです。
Gibron

169

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

DELETE要求メッセージ内のペイロードには、意味が定義されていません。DELETEリクエストでペイロード本体を送信すると、一部の既存の実装がリクエストを拒否する可能性があります。


3
仕様の最新の未承認バージョンでは、この要件は削除されています。最新の承認済みバージョンは、上記のRFC2616のままです。
BishopZ 2012

4
どのバージョン?バージョン20は、上記でリンクしたバージョン19と同じ文言をまだ持っています。
grzes

11
ボディを許可できるというバージョン26の提案:A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.下位互換性の警告が付属しているため、次の標準が言っていることを示唆しています。DELETEボディを持つことができます `。
Pure.Krome

4
RFC 7231セクション4.3.5では、バージョン26の言語をで確定していますA payload within a DELETE request message has no defined semantics。だから体は許される。
mndrix 2017年

6
本文は許可されますが、リクエストに関連するものであってはなりません。それを使用してもまったく意味がありません。
エバート

54

TomcatとJettyの一部のバージョンでは、エンティティボディが存在しても無視されます。あなたがそれを受け取るつもりなら、それは迷惑になることができます。


2
Google App Engineは、リクエスト本文の代わりに空のデフォルトエンティティをインスタンス化して渡します。
Oliver Hausler、


50

削除リクエストで本文を使用する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;
    }
}

15
GET(およびDELETE)にボディがあると、HTTPとRESTが明らかに誤用されます。同時実行制御を処理するメカニズムは他にもあります(例:If-Modified-Sinceおよびetags)。
Bruno

19
仕様がDELETEで本体を禁止しない場合、それを明らかに誤って扱いますか?
Neil McGuigan、2013

5
あなたは身体で何かをするつもりはないからです。See:stackoverflow.com/a/983458/372643
Bruno

14
これはまったく同じ問題です。GETではURIで識別されるリソースの表現を取得でき、DELETEではURIで識別されるリソースを削除します。特定のバージョンを削除する場合は、他のバージョンに別のURIを使用してください。URIは、HTTP / REST内のリソースの唯一の識別子である必要があります。同時実行性を処理する必要がある場合は、ヘッダーでメタデータを使用します(If-Unmodified-SinceまたはEtag、それが目的です)。
ブルーノ

5
本文のバージョンフィールドの代わりにETagヘッダーを使用する
マルハル2015

26

ように私には見えるRFC 2616はこれを指定していません。

セクション4.3から:

リクエスト内のメッセージ本文の存在は、リクエストのメッセージヘッダーにContent-LengthまたはTransfer-Encodingヘッダーフィールドを含めることで通知されます。リクエストメソッドの仕様(セクション5.1.1)がリクエストでのエンティティボディの送信を許可しない場合、メッセージボディをリクエストに含めることはできません。サーバーは、あらゆるリクエストでメッセージ本文を読み取って転送する必要があります。リクエストメソッドにエンティティボディの定義されたセマンティクスが含まれていない場合、リクエストを処理するときにメッセージボディを無視する必要があります(SHOULD)。

そしてセクション9.7:

DELETEメソッドは、起点サーバーがRequest-URIで識別されるリソースを削除することを要求します。このメソッドは、オリジンサーバーでの人間の介入(または他の手段)によってオーバーライドされる場合があります。オリジンサーバーから返されたステータスコードがアクションが正常に完了したことを示している場合でも、クライアントは操作が実行されたことを保証できません。ただし、サーバーは、応答が与えられたときにリソースを削除するか、アクセスできない場所に移動することを意図していない限り、成功を示すべきではありません(SHOULD NOT)。

成功した応答は、応答にステータスを説明するエンティティが含まれている場合は200(OK)、アクションがまだ実行されていない場合は202(承認済み)、アクションが実行されているが応答に含まれていない場合は204(コンテンツなし)であるべきです(SHOULD)。エンティティ。

リクエストがキャッシュを通過し、Request-URIが現在キャッシュされている1つ以上のエンティティを識別する場合、それらのエントリは古いものとして扱われる必要があります(SHOULD)。このメソッドへの応答はキャッシュできません。

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


19

ヘッドアップです。DELETEリクエストで本文を指定し、Google Cloud HTTPSロードバランサーを使用している場合、400エラーでリクエストが拒否されます。私は頭を壁にぶつけて、Googleが何らかの理由で、本文を含むDELETE要求は不正な形式の要求であると考えていることを発見しました。


1
for whatever reason-仕様にそのように記載されているため:P
Mardoxx 2018

20
仕様は「そう言っている」わけではなく、本体が明確に定義されていないことを示しているだけです。定義されておらず、それを無視したい場合は、クールに...無視してください。しかし、要求を完全に拒否することは極端で不必要なようです。
Ben Fried、

1
未定義の動作に依存しないでください。これはかなり一般的なベストプラクティスです。
エバート

@Evert明示的に定義されていない動作(たとえば、C言語の仕様で説明を参照)があり、許可されているが単に説明されていない動作があります。メッセージ本文の使用DELETEは後者です。
アルニタク

9

バージョン3.0のOpenAPI仕様では、本文付きのDELETEメソッドのサポートが廃止されたことに注意してください。

参照についてはここここを参照してください

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


7

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

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

コメントで言及されているように、もうそうではないかもしれません


1
Apache HTTPクライアントを使用する場合、HttpEntityEnclosingRequestBaseを拡張し、getMethod()メソッドがGETまたはDELETEを返すようにすることで、独自のバージョンのGETおよびDELETEを簡単に作成できます。これをelasticsearchとの会話に使用します。
Jilles van Gurp、2015

2
デッドリンク-素晴らしい。私たちはそれらのリンクの答えをもっと必要としています
コットンで

3
リンクされたドキュメントには、POSTリクエストのみが含まれ、DELETEは含まれなくなりました。この回答にメモを追加する価値がありますか?
dshepherd 2017年

Elasticsearchは、GETリクエストでも本文を使用します。
Nidhin David、

7

HTTPメーリングリストのロイフィールディングは、httpメーリングリストhttps://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.htmlで次のように明言しています :

GET / DELETE本文は、リクエストの処理または解釈に影響を与えることは絶対に禁止されています

これは、本体がサーバーの動作を変更してはならないことを意味します。次に彼は追加します:

メッセージのフレーミングを維持するために受信したバイトを読み取って破棄する必要性は別として。

そして最後に、身体を禁じない理由:

ボディの送信を禁止しなかった唯一の理由は、ボディが送信されないことを想定した遅延実装につながるためです。

したがって、クライアントはペイロードボディを送信できますが、サーバーはそれをドロップし、APIはこれらのリクエストのペイロードボディのセマンティクスを定義しないでください。


5

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

DELETE要求メッセージ内のペイロードには、意味が定義されていません。DELETEリクエストでペイロード本体を送信すると、一部の既存の実装がリクエストを拒否する可能性があります。
https://tools.ietf.org/html/rfc7231#page-29



3
この正確な引用は以前の回答にすでに含まれています。この回答は削除する必要があります。
Madbreaks、

5

本文でDELETEを使用するのは危険です... RESTよりもリスト操作の場合は、このアプローチを好みます。

定期的な運用

GET / objects / すべてのオブジェクトを取得します

GET / object / ID 指定されたIDのオブジェクトを取得します

POST / objects 新しいオブジェクトを追加します

PUT / object / ID 指定されたIDのオブジェクトを追加し、オブジェクトを更新します

DELETE / object / ID 指定されたIDのオブジェクトを削除します

すべてのカスタムアクションはPOSTです

POST / objects / addList 本文に含まれるオブジェクトのリストまたは配列を追加します

POST / objects / deleteList 本文に含まれるオブジェクトのリストを削除します

POST / objects / customQuery 本文のカスタムクエリに基づいてリストを作成します

クライアントが拡張操作をサポートしていない場合、通常の方法で動作できます。


POST特にLocationヘッダーのコンテキストでは、POST応答のセマンティクスが不明確であるため、a を使用することは、新しいリソースを作成するための適切なRESTy方法ではありません。基本的にHTTPを残し、RPCをスタックします。適切な「HTTP / RESTの方法」はPUTIf-None-Match: *ヘッダーを使用してリソースを作成することです(または適切なHTTPメソッドを指定する、MKCOLなどを参照)。
hnh

4

これに対する良い答えは投稿されていないと思いますが、既存の答えについては素晴らしいコメントがたくさんあります。これらのコメントの要点を新しい答えに引き上げます。

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

DELETE要求メッセージ内のペイロードには、意味が定義されていません。DELETEリクエストでペイロード本体を送信すると、一部の既存の実装がリクエストを拒否する可能性があります。

他の答えから逃したのはその含意でした。はい、DELETEリクエストに本文を含めることはできますが、意味的には意味がありません。これが実際に意味することはDELETE、リクエスト本文を使用してリクエストを発行することは、意味的にはリクエスト本文を含めないことと同じです。

リクエストボディを含めてもリクエストには影響がないため、含めても意味がありません。

tl; dr:技術的にはDELETEリクエスト本文を含むリクエストが許可されますが、そうすることは決して役に立ちません。


2
「意味的に無意味」とは、「意味が定義されていない」と同じ意味ではありません。前者は意味がないことを意味します。後者は単にRFC自体がそれらのセマンティクスが何であるかを指定していないことを意味します。(私はRFCを作成します)
アルニタク

1
つまり、APIの実装者がいくつかのセマンティクスを自分で定義したい場合、完全に自由に定義できます。
アルニタク

1
@Alnitakこれは間違いなく誤解です。その定義では、どの HTTPリクエストボディにもセマンティクスは定義されていませんが、仕様ではDELETEおよびGETが明確に呼び出されています。ここでGETリクエストについては、特にこのの話はまだツー・公開されることはドラフトからの抜粋です:
エバート

1
これは現在リリースされているRFCで不明確であることには同意しませんが、私を信じていない場合は、著者にDELETEおよびGETの意図を聞いてから依頼することを勧めます。あなたはそれが私の答えと一致することがわかります。あなたと同じように、私は標準化団体にも関わっており、RFCをどのように解釈すべきかについて意見を持つのは私だけではありません。
エバート

2
その場合は、7231の文言が不適切であり、「ペイロード本体は無視する必要がある」と述べているはずです。上記のどのドラフトを参照していますか?
アルニタク

3

誰かがこの問題のテストを実行している場合、それは普遍的にサポートされていません。

私は現在Sahi Proでテストしていますが、http DELETE呼び出しにより、提供された本文データ(エンドポイントの設計に従って大量に削除するIDの大きなリスト)が取り除かれていることは明らかです。

私は何度か彼らと連絡を取り、3つの個別のパッケージのパッケージ、画像、ログを送って彼らが確認できるようにしましたが、彼らはまだこれを確認していません。パッチが失敗し、後でサポートが電話に出られなかったため、確実な答えが得られません。

Sahiはこれをサポートしていないと思います。他の多くのツールがスイートに続くと思います。


Sahi Proの最新バージョンに実装されています。SahiはJavaを使用してHTTP呼び出しを行うため、Javaにはバージョン1.8より前のバグがあり、ユーザーがDELETE要求を行うことができませんでした。したがって、Java 1.8以降とSahi Pro 6.1.1(近日公開予定)では、Sahiでbodyを使用してDELETEリクエストを行うことができます。
Vivek V Dwivedi

-1

以下のGitHUbのURLが答えを得るのに役立ちます。実際、TomcatのようなApplication Server、WeblogicはリクエストペイロードによるHTTP.DELETE呼び出しを拒否しています。これらすべてを念頭に置いて、私はgithubに例を追加しました。

https://github.com/ashish720/spring-examples


-1

リクエスト本文を使用してDELETE操作を実装できました。AWS LambdaとAWS APIゲートウェイを使用し、Go言語を使用しました。


3
彼らは能力ではなく標準について話している。あなたはボディでGETリクエストを持つことさえできます、それは良くありません
ReZa
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.