Apakah badan entitas diizinkan untuk permintaan HTTP DELETE?

717

Saat mengeluarkan permintaan HTTP DELETE, URI permintaan harus sepenuhnya mengidentifikasi sumber daya yang akan dihapus. Namun, apakah dapat menambahkan meta-data tambahan sebagai bagian dari badan entitas permintaan?

Haacked
sumber
4
Dalam ASP.NET WebApi 2 FromBody Parameters diabaikan untuk titik akhir HttpDelete.
Jenny O'Reilly
2
Saya memiliki keprihatinan yang sama, tetapi kasus saya berbeda. Saya ingin mengeluarkan permintaan penghapusan batch ketika saya ingin menghapus ratusan objek. Tentu saja ini merupakan peningkatan kinerja yang luar biasa untuk jaringan pra HTTP 2.0.
Singagirl
1
Apakah ada perubahan pada HTTP / 2?
Jyotman Singh

Jawaban:

570

Spek tidak secara eksplisit melarang atau mengecilkannya, jadi saya cenderung mengatakan itu diizinkan.

Microsoft melihatnya dengan cara yang sama (saya dapat mendengar gumaman di antara hadirin), mereka menyatakan dalam artikel MSDN tentang Metode DELETE dari ADO.NET Framework Layanan Data :

Jika permintaan DELETE termasuk badan entitas, tubuh diabaikan [...]

Selain itu, inilah yang dikatakan RFC2616 (HTTP 1.1) sehubungan dengan permintaan:

  • sebuah entitas-tubuh hanya hadir ketika pesan-tubuh hadir (bagian 7.2)
  • keberadaan badan pesan ditandai dengan dimasukkannya header Content-Lengthatau Transfer-Encoding(bagian 4.3)
  • badan pesan tidak boleh disertakan ketika spesifikasi metode permintaan tidak memungkinkan pengiriman entitas badan (bagian 4.3)
  • sebuah entitas-tubuh secara eksplisit dilarang dalam TRACE permintaan saja, semua jenis permintaan lainnya tidak dibatasi (bagian 9, dan 9,8 secara khusus)

Untuk tanggapan, ini telah didefinisikan:

  • apakah badan pesan disertakan tergantung pada metode permintaan dan status respons (bagian 4.3)
  • badan pesan secara eksplisit dilarang dalam menanggapi permintaan HEAD (bagian 9, dan 9.4 khusus)
  • badan pesan secara eksplisit dilarang di 1xx (informasi), 204 (tidak ada konten), dan 304 (tidak dimodifikasi) tanggapan (bagian 4.3)
  • semua respons lain termasuk badan pesan, meskipun panjangnya mungkin nol (bagian 4.3)
Tomalak
sumber
7
@ Alasan Pasti. Anda juga dapat menggunakan tajuk khusus untuk meneruskan data tambahan, tetapi mengapa tidak menggunakan badan permintaan.
Tomalak
86
Meskipun spesifikasi tidak melarang permintaan DELETE dari memiliki badan pesan, bagian 4.3 tampaknya menunjukkan bahwa badan harus diabaikan oleh server karena tidak ada "semantik yang ditentukan" untuk badan entitas DELETE : "Server HARUS membaca dan meneruskan sebuah badan pesan pada permintaan apa pun; jika metode permintaan tidak menyertakan semantik yang ditentukan untuk badan entitas, maka badan pesan HARUS diabaikan ketika menangani permintaan . "
shelley
72
Harap dicatat bahwa banyak klien juga tidak dapat mengirim DELETE dengan sebuah badan. Ini baru saja membakar saya di Android.
Karmic Coder
1
@KarmicCoder: Poin bagus. Info lebih lanjut: Mengirim permintaan HTTP DELETE di Android .
MS Dousti
2
Banyak diskusi tentang implementasi dicampur dengan spec HTTP. Klien akan mengimplementasikan hal-hal dengan cara mereka menginterpretasikan spec, jangan membingungkan ini dengan arti spec. Faktanya adalah bahwa spesifikasi meninggalkan ini ambigu. Saya tidak setuju dengan interpretasi bahwa karena tidak ada semantik yang pasti untuk entitas-tubuh, maka ada implikasi bahwa itu harus diabaikan. Saya pikir orang-orang bekerja mundur dari interpretasi spesifik klien yang ada (Jersey, klien pengujian Android, dll) dan mencoba untuk membenarkan interpretasi daripada berusaha untuk jujur ​​pada spec. Manusia bisa keliru.
Gibron
169

Pembaruan terbaru untuk spesifikasi HTTP 1.1 ( RFC 7231 ) secara eksplisit memungkinkan badan entitas dalam permintaan DELETE:

Muatan dalam pesan permintaan DELETE tidak memiliki semantik yang ditentukan; mengirimkan badan muatan pada permintaan DELETE dapat menyebabkan beberapa implementasi yang ada menolak permintaan tersebut.

grzes
sumber
3
versi terakhir dari spesifikasi yang tidak disetujui menghapus persyaratan ini. Versi terbaru yang disetujui masih merupakan RFC2616 yang dikutip di atas.
BishopZ
4
Versi yang mana? Versi 20 masih memiliki kata-kata yang sama dengan versi 19 yang saya tautkan di atas: "Badan pada permintaan DELETE tidak memiliki semantik yang ditentukan. Perhatikan bahwa mengirim badan pada permintaan DELETE dapat menyebabkan beberapa implementasi yang ada untuk menolak permintaan."
grzes
11
Versi 26 menyarankan agar Anda dapat mengizinkan sebuah badan: 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.Jadi ia datang dengan peringatan kompatibilitas mundur, menyarankan bahwa standar berikutnya akan mengatakan: 'ya! DELETEdapat memiliki tubuh`.
Pure.Krome
4
RFC 7231 bagian 4.3.5 menyelesaikan bahasa dari versi 26 dengan A payload within a DELETE request message has no defined semantics. Jadi tubuh diizinkan.
mndrix
6
Badan diizinkan tetapi tidak boleh relevan dengan permintaan. Sama sekali tidak ada gunanya menggunakannya.
Evert
55

Beberapa versi Tomcat dan Jetty tampaknya mengabaikan badan entitas jika ada. Yang bisa menjadi gangguan jika Anda bermaksud menerimanya.

evan.leonard
sumber
2
Google App Engine instantiate dan melewati entitas default kosong alih-alih badan permintaan.
Oliver Hausler
Informasi lebih lanjut tentang Tomcat: Cara membuat Apache Tomcat menerima metode DELETE .
MS Dousti
50

Salah satu alasan untuk menggunakan tubuh dalam permintaan penghapusan adalah untuk kontrol konkurensi optimis.

Anda membaca versi 1 dari catatan.

GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

Rekan Anda membaca versi 1 dari catatan.

GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

Kolega Anda mengubah catatan dan memperbarui database, yang memperbarui versi ke 2:

PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }

Anda mencoba menghapus catatan:

DELETE /some-resource/1 { id:1, version:1 }
409 Conflict

Anda harus mendapatkan pengecualian kunci optimis. Baca kembali catatan, lihat bahwa ini penting, dan mungkin tidak menghapusnya.

Alasan lain untuk menggunakannya adalah untuk menghapus beberapa catatan sekaligus (misalnya, kotak dengan kotak centang pemilihan baris).

DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content

Perhatikan bahwa setiap pesan memiliki versinya sendiri. Mungkin Anda dapat menentukan beberapa versi menggunakan beberapa tajuk, tetapi menurut George, ini lebih sederhana dan jauh lebih nyaman.

Ini berfungsi di Tomcat (7.0.52) dan Spring MVC (4.05), mungkin juga versi sebelumnya:

@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}
Neil McGuigan
sumber
15
Memiliki tubuh di GET (dan HAPUS) jelas memperlakukan HTTP dan REST. Ada mekanisme lain untuk menangani kontrol konkurensi (misalnya If-Modified-Sejak dan etag).
Bruno
19
Bagaimana itu dengan sangat jelas memperlakukannya ketika spec tidak melarang tubuh di DELETE?
Neil McGuigan
5
Karena Anda tidak seharusnya melakukan apa pun dengan tubuh. Lihat: stackoverflow.com/a/983458/372643
Bruno
14
Ini persis masalah yang sama: GET memungkinkan Anda untuk mengambil representasi sumber daya yang diidentifikasi oleh URI, dan DELETE menghapus sumber daya yang diidentifikasi oleh URI. Gunakan URI yang berbeda untuk versi lain jika Anda ingin menghapus versi tertentu. URI harus menjadi satu-satunya pengidentifikasi sumber daya dalam HTTP / REST. Gunakan metadata di header jika Anda perlu menangani konkurensi (misalnya , If-Unmodified-Sinceatau Etaguntuk itulah itu tujuan).
Bruno
5
Gunakan tajuk ETag sebagai ganti bidang versi di badan
malhal
26

Tampak bagi saya bahwa RFC 2616 tidak menentukan ini.

Dari bagian 4.3:

Kehadiran badan pesan dalam permintaan ditandai dengan dimasukkannya bidang Konten-Panjang atau Transfer-Pengkodean dalam header pesan permintaan. Badan pesan TIDAK HARUS dimasukkan dalam permintaan jika spesifikasi metode permintaan (bagian 5.1.1) tidak memungkinkan pengiriman badan hukum dalam permintaan. Server HARUS membaca dan meneruskan badan pesan atas permintaan apa pun; jika metode permintaan tidak termasuk semantik yang ditentukan untuk badan-badan, maka badan pesan HARUS diabaikan ketika menangani permintaan.

Dan bagian 9.7:

Metode DELETE meminta server asal menghapus sumber yang diidentifikasi oleh Request-URI. Metode ini DAPAT ditimpa oleh intervensi manusia (atau cara lain) pada server asal. Klien tidak dapat dijamin bahwa operasi telah dilakukan, bahkan jika kode status yang dikembalikan dari server asal menunjukkan bahwa tindakan telah berhasil diselesaikan. Namun, server TIDAK HARUS menunjukkan keberhasilan kecuali, pada saat respon diberikan, itu bermaksud untuk menghapus sumber daya atau memindahkannya ke lokasi yang tidak dapat diakses.

Respons yang berhasil HARUS menjadi 200 (OK) jika respons mencakup entitas yang menggambarkan status, 202 (Diterima) jika tindakan belum diberlakukan, atau 204 (Tidak Ada Konten) jika tindakan telah diberlakukan tetapi respons tidak termasuk sebuah entitas.

Jika permintaan melewati cache dan Request-URI mengidentifikasi satu atau lebih entitas yang di-cache saat ini, entri-entri tersebut HARUS diperlakukan sebagai basi. Respons terhadap metode ini tidak dapat di-cache.c

Jadi itu tidak diizinkan atau dianulir secara eksplisit, dan ada kemungkinan proxy sepanjang jalan dapat menghapus isi pesan (meskipun HARUS membaca dan meneruskannya).

Adam Rosenfield
sumber
19

Hanya kepala, jika Anda menyediakan tubuh dalam permintaan DELETE Anda dan menggunakan load balancer Google cloud HTTPS, itu akan menolak permintaan Anda dengan kesalahan 400. Saya membenturkan kepala ke dinding dan mengetahui bahwa Google, untuk alasan apa pun, menganggap permintaan DELETE dengan tubuh adalah permintaan yang cacat.

Ben Fried
sumber
1
for whatever reason- karena spek mengatakan demikian: P
Mardoxx
20
Spesifikasinya tidak "mengatakan demikian", hanya mengatakan bahwa bodinya tidak didefinisikan secara spesifik. Jika tidak ditentukan, dan Anda ingin mengabaikannya, dinginkan ... lanjutkan saja. Tetapi menolak permintaan itu tampaknya ekstrem dan tidak perlu.
Ben Fried
1
Jangan mengandalkan perilaku yang tidak terdefinisi. Ini praktik terbaik yang cukup umum.
Evert
@ Balikkan ada perilaku yang tidak terdefinisi secara eksplisit (seperti yang Anda lihat jelaskan dalam spesifikasi bahasa C misalnya) dan ada perilaku yang diizinkan tetapi tidak dijelaskan. Menggunakan badan pesan di DELETEadalah yang terakhir.
Alnitak
9

Perlu dicatat bahwa spesifikasi OpenAPI untuk versi 3.0 menjatuhkan dukungan untuk metode DELETE dengan sebuah body:

lihat di sini dan di sini untuk referensi

Ini dapat memengaruhi implementasi, dokumentasi, atau penggunaan API Anda di masa mendatang.

CleverPatrick
sumber
7

Tampaknya ElasticSearch menggunakan ini: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

Yang berarti Netty mendukung ini.

Seperti disebutkan dalam komentar itu mungkin tidak lagi terjadi

Sebastien Lorber
sumber
1
Jika Anda menggunakan apache http client, Anda dapat dengan mudah membuat versi GET dan DELETE Anda sendiri dengan memperluas HttpEntityEnclosingRequestBase dan membuat metode getMethod () mengembalikan GET atau DELETE. Kami menggunakan ini untuk berbicara dengan elasticsearch.
Jilles van Gurp
2
tautan mati - hebat. kita membutuhkan lebih banyak jawaban tautan tersebut - bukan
cottton
3
Dokumentasi tertaut sekarang hanya berisi permintaan POST, tidak ada HAPUS. Mungkinkah menambahkan catatan pada jawaban ini?
dshepherd
Elasticsearch menggunakan badan dengan permintaan GET juga.
Nidhin David
7

Roy Fielding pada milis HTTP mengklarifikasi bahwa pada milis http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html dan mengatakan:

Badan GET / DELETE benar-benar dilarang memiliki dampak apa pun terhadap pemrosesan atau interpretasi permintaan

Ini berarti bahwa tubuh tidak boleh memodifikasi perilaku server. Lalu dia menambahkan:

selain dari keharusan untuk membaca dan membuang byte yang diterima untuk menjaga pembingkaian pesan.

Dan akhirnya alasan untuk tidak melarang tubuh:

Satu-satunya alasan kami tidak melarang pengiriman tubuh adalah karena itu akan menyebabkan implementasi yang malas dengan asumsi tidak ada tubuh yang akan dikirim.

Jadi, sementara klien dapat mengirim badan muatan, server harus menjatuhkannya dan API tidak boleh menetapkan semantik untuk badan muatan pada permintaan tersebut.

Roberto Polli
sumber
5

Ini tidak didefinisikan .

Muatan dalam pesan permintaan DELETE tidak memiliki semantik yang ditentukan; mengirimkan badan muatan pada permintaan DELETE dapat menyebabkan beberapa implementasi yang ada menolak permintaan tersebut.
https://tools.ietf.org/html/rfc7231#page-29

Simon Jin
sumber
Secara khusus, RFC 7231 bagian 4.3.5
mndrix
3
Kutipan yang tepat ini sudah termasuk dalam jawaban sebelumnya, jawaban ini harus dihapus.
Madbreaks
5

Menggunakan DELETE with a Body berisiko ... Saya lebih suka pendekatan ini untuk Operasi Daftar daripada REST:

Operasi Reguler

DAPATKAN / objek / Mendapat semua Objek

DAPATKAN / objek / ID Mendapat Objek dengan ID yang ditentukan

POST / objek Menambahkan Objek baru

PUT / objek / ID Menambahkan Objek dengan ID yang ditentukan, Memperbarui Objek

HAPUS / objek / ID Menghapus objek dengan ID yang ditentukan

Semua tindakan Kustom adalah POST

POST / objek / addList Menambahkan Daftar atau Array Objek yang termasuk dalam tubuh

POST / objek / deleteList Menghapus Daftar Objek yang termasuk dalam tubuh

POST / objek / customQuery Membuat Daftar berdasarkan permintaan kustom di tubuh

Jika klien tidak mendukung operasi Anda yang diperluas, mereka dapat bekerja secara teratur.

Eliezer Garza
sumber
Menggunakan a POSTbukanlah cara RESTy yang baik untuk menciptakan sumber daya baru karena semantik respons POST tidak jelas, terutama dalam konteks header Lokasi. Anda pada dasarnya meninggalkan HTTP dan menumpuk RPC di atasnya. "HTTP / REST way" yang tepat adalah membuat sumber daya menggunakan PUTw / If-None-Match: *header (atau menentukan metode HTTP yang tepat, lihat MKCOLdll).
hnh
4

Saya tidak berpikir jawaban yang bagus untuk ini telah diposting, meskipun ada banyak komentar bagus pada jawaban yang ada. Saya akan mengangkat inti dari komentar-komentar itu menjadi jawaban baru:

Paragraf ini dari RFC7231 telah dikutip beberapa kali, yang memang meringkasnya.

Muatan dalam pesan permintaan DELETE tidak memiliki semantik yang ditentukan; mengirimkan badan muatan pada permintaan DELETE dapat menyebabkan beberapa implementasi yang ada menolak permintaan tersebut.

Apa yang saya lewatkan dari jawaban lain adalah implikasinya. Ya itu diizinkan untuk memasukkan badan pada DELETEpermintaan, tetapi secara semantik tidak berarti. Apa ini sebenarnya berarti bahwa mengeluarkan DELETEpermintaan dengan badan permintaan secara semantik setara dengan tidak termasuk badan permintaan.

Termasuk badan permintaan tidak akan berpengaruh pada permintaan, jadi tidak pernah ada gunanya memasukkannya.

tl; dr: Secara teknis DELETEpermintaan dengan badan permintaan diizinkan, tetapi tidak pernah berguna untuk melakukannya.

Evert
sumber
2
"semantik tidak berarti" tidak berarti sama dengan "tidak memiliki semantik yang ditentukan". Yang pertama berarti bahwa itu tidak dapat memiliki makna. Yang terakhir hanya berarti bahwa RFC itu sendiri tidak menentukan apa semantik itu mungkin. (Saya menulis RFC)
Alnitak
1
Dengan kata lain, jika implementor API ingin mendefinisikan beberapa semantik untuk dirinya sendiri, mereka sepenuhnya bebas untuk melakukannya.
Alnitak
1
@Alnitak ini jelas merupakan interpretasi yang salah. Menurut definisi itu, setiap badan permintaan HTTP tidak memiliki semantik yang ditentukan, tetapi HAPUS dan DAPATKAN secara spesifik disebut dalam spesifikasi. Berikut cuplikan dari draft yang belum dipublikasikan yang membahas tentang ini secara khusus tentang permintaan GET:
Evert
1
Saya tidak setuju dengan Anda bahwa ini tidak jelas dalam RFC yang saat ini dirilis, tetapi jika Anda tidak percaya, saya akan mengundang Anda untuk bertanya kepada penulis setelah niat mereka untuk DELETE dan GET. Anda akan menemukan bahwa itu sesuai dengan jawaban saya. Seperti Anda, saya juga terlibat dalam badan standar dan saya bukan hanya orang yang sendirian dengan pendapat tentang bagaimana RFC harus ditafsirkan.
Evert
2
Jika itu yang terjadi maka 7231 adalah kata-kata yang buruk, dan seharusnya mengatakan "badan muatan HARUS diabaikan". Draf apa yang Anda maksud di atas?
Alnitak
3

Jika ada yang mengalami pengujian masalah ini, Tidak, itu tidak didukung secara universal.

Saat ini saya sedang menguji dengan Sahi Pro dan sangat jelas panggilan http DELETE menghapus data tubuh yang disediakan (daftar besar id untuk dihapus secara massal sesuai desain titik akhir).

Saya telah melakukan kontak dengan mereka beberapa kali dan juga mengirim dalam tiga paket skrip, gambar, log untuk mereka tinjau dan mereka masih belum mengonfirmasi hal ini. Tambalan yang gagal, dan panggilan konferensi yang tidak terjawab oleh dukungan mereka kemudian dan saya masih belum mendapatkan jawaban yang solid.

Saya yakin Sahi tidak mendukung ini, dan saya akan membayangkan banyak alat lain mengikuti suite.

parker
sumber
Ini diimplementasikan dalam versi terbaru Sahi Pro. Karena Sahi menggunakan java untuk melakukan panggilan HTTP, dan Java memiliki bug sebelum versi 1.8 yang tidak akan membiarkan pengguna membuat permintaan DELETE. Jadi dengan Java 1.8 dan seterusnya dan Sahi Pro 6.1.1 (untuk umum segera), orang dapat membuat permintaan DELETE dengan badan di Sahi.
Vivek V Dwivedi
-1

Mungkin url GitHUb di bawah ini akan membantu Anda, untuk mendapatkan jawabannya. Sebenarnya, Application Server seperti Tomcat, Weblogic menolak panggilan HTTP.DELETE dengan permintaan payload. Jadi dengan mengingat semua hal ini, saya telah menambahkan contoh di github, tolong perhatikan

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

Ashish
sumber
-1

Saya dapat menerapkan operasi DELETE dengan badan Permintaan. Saya menggunakan AWS Lambda dan AWS API gateway dan menggunakan bahasa Go.

Dattatray
sumber
3
Mereka berbicara tentang standar, bukan kemampuan. Anda bahkan dapat memiliki permintaan GET dengan tubuh, yang tidak baik
ReZa