HTTP DAPATKAN dengan badan permintaan

2111

Saya sedang mengembangkan layanan web RESTful baru untuk aplikasi kita.

Saat melakukan GET pada entitas tertentu, klien dapat meminta konten entitas. Jika mereka ingin menambahkan beberapa parameter (misalnya mengurutkan daftar) mereka dapat menambahkan parameter ini dalam string kueri.

Atau saya ingin orang dapat menentukan parameter ini di badan permintaan. HTTP / 1.1 tampaknya tidak secara eksplisit melarang ini. Ini akan memungkinkan mereka untuk menentukan lebih banyak informasi, mungkin membuatnya lebih mudah untuk menentukan permintaan XML yang kompleks.

Pertanyaan saya:

  • Apakah ini ide yang bagus?
  • Apakah klien HTTP akan mengalami masalah dengan menggunakan badan permintaan dalam permintaan GET?

http://tools.ietf.org/html/rfc2616

Evert
sumber
552
Keuntungannya adalah memungkinkan pengiriman tubuh permintaan XML atau JSON dengan mudah, tidak memiliki batasan panjang dan lebih mudah untuk disandikan (UTF-8).
Evert
29
Jika yang Anda cari adalah metode yang aman dan idempoten yang memungkinkan badan permintaan, Anda mungkin ingin melihat SEARCH, PROPFIND, dan LAPORAN. Tentu saja tidak menggunakan GET dan meminta tubuh mengalahkan caching kurang lebih.
Julian Reschke
226
@fijiaaron: 3 tahun kemudian, dan sejak itu saya mendapatkan banyak pengalaman menulis layanan web. Ini pada dasarnya semua yang telah saya lakukan selama beberapa tahun terakhir. Saya bisa mengatakan dengan aman, itu memang ide yang sangat buruk untuk menambahkan tubuh ke permintaan GET. Dua jawaban teratas berdiri seperti batu.
Evert
26
@ Ellesedil: Sederhananya: Apa pun kelebihan yang ada untuk menggunakan GET over POST, ada karena bagaimana HTTP dirancang. Keuntungan itu tidak ada lagi, ketika Anda melanggar standar dengan cara ini. Karena itu, hanya ada satu alasan lagi untuk menggunakan GET + badan permintaan alih-alih POST: Estetika. Jangan mengorbankan desain yang kuat di atas estetika.
Malam
7
Untuk menggarisbawahi apa yang dikatakan Evert: "itu tidak memiliki batasan panjang". Jika GET Anda dengan parameter kueri melanggar batasan panjang (tahun 2048), lalu apa pilihan lain selain meletakkan informasi string kueri dalam objek json, misalnya, di badan permintaan.
Kieran Ryan

Jawaban:

1726

Komentar Roy Fielding tentang memasukkan badan dengan permintaan GET .

Iya. Dengan kata lain, pesan permintaan HTTP apa pun diizinkan mengandung badan pesan, dan karenanya harus mem-parsing pesan dengan itu. Semantik server untuk GET, bagaimanapun, dibatasi sedemikian rupa sehingga suatu badan, jika ada, tidak memiliki makna semantik terhadap permintaan tersebut. Persyaratan parsing terpisah dari persyaratan semantik metode.

Jadi, ya, Anda dapat mengirim tubuh dengan GET, dan tidak, itu tidak pernah berguna untuk melakukannya.

Ini adalah bagian dari desain berlapis HTTP / 1.1 yang akan menjadi jelas kembali setelah spesifikasi dipartisi (sedang dalam proses pengerjaan).

.... Roy

Ya, Anda dapat mengirim badan permintaan dengan GET tetapi itu tidak memiliki arti. Jika Anda memberi makna dengan menguraikannya di server dan mengubah respons Anda berdasarkan isinya , maka Anda mengabaikan rekomendasi ini dalam spec HTTP / 1.1, bagian 4.3 :

[...] jika metode permintaan tidak menyertakan semantik yang ditentukan untuk badan-entitas, maka badan pesan HARUS diabaikan ketika menangani permintaan.

Dan deskripsi metode GET dalam spec HTTP / 1.1, bagian 9.3 :

Metode GET berarti mengambil informasi apa pun ([...]) yang diidentifikasi oleh Request-URI.

yang menyatakan bahwa badan permintaan bukan bagian dari identifikasi sumber daya dalam permintaan GET, hanya URI permintaan.

Pembaruan RFC2616 yang dirujuk sebagai "HTTP / 1.1 spec" sekarang sudah usang. Pada 2014 itu digantikan oleh RFCs 7230-7237. Kutipan "badan pesan HARUS diabaikan ketika menangani permintaan" telah dihapus. Sekarang hanya "Membingkai pesan permintaan tidak tergantung pada semantik metode, bahkan jika metode tersebut tidak mendefinisikan penggunaan untuk badan pesan" Kutipan kedua "Metode GET berarti mengambil informasi apa pun ... yang diidentifikasi oleh Request-URI" telah dihapus. - Dari komentar

Paul Morgan
sumber
72
Caching / proxying adalah dua hal yang paling mungkin Anda hancurkan, ya. "Semantik" hanyalah cara lain untuk mengatakan "cara orang yang membuat komponen lain akan mengharapkan komponen lain beroperasi". Jika Anda melanggar semantik, Anda lebih cenderung melihat hal-hal pecah di tempat-tempat orang menulis hal-hal yang diharapkan Anda menghormati semantik tersebut.
Stuart P. Bentley
109
Elasticsearch adalah produk yang cukup besar yang memanfaatkan badan permintaan HTTP di GET. Menurut manual mereka apakah permintaan HTTP harus mendukung memiliki tubuh atau tidak tidak ditentukan. Saya pribadi tidak nyaman dengan mengisi badan permintaan GET, tetapi mereka tampaknya memiliki pendapat yang berbeda dan mereka harus tahu apa yang mereka lakukan. elastic.co/guide/en/elasticsearch/guide/current/...
GordonM
26
@ iwein memberi GET arti tubuh permintaan sebenarnya bukan pelanggaran spesifikasi. HTTP / 1.1 menetapkan bahwa server HARUS mengabaikan tubuh, tetapi RFC 2119 menetapkan bahwa pelaksana diizinkan untuk mengabaikan klausa "HARUS" jika mereka memiliki alasan yang baik untuk melakukannya. Sebaliknya, klien tidak melanggar spec jika mengasumsikan bahwa mengubah tubuh GET akan tidak mengubah respon.
Emil Lundberg
108
RFC2616 yang dirujuk sebagai "HTTP / 1.1 spec" sekarang sudah usang. Pada 2014 itu digantikan oleh RFCs 7230-7237. Kutipan " badan pesan HARUS diabaikan ketika menangani permintaan " telah dihapus . Sekarang hanya " Membingkai pesan permintaan tidak tergantung pada semantik metode, bahkan jika metode tersebut tidak mendefinisikan penggunaan apa pun untuk badan pesan " Kutipan kedua " Metode GET berarti mengambil informasi apa pun ... yang diidentifikasi oleh Request-URI " telah dihapus . Jadi, saya sarankan untuk mengedit jawaban @Jarl
Artem Nakonechny
29
Saya tahu bahwa ini adalah utas lama - saya sengaja menemukannya. @Artem Nakonechny secara teknis benar tetapi spec baru mengatakan "Muatan dalam pesan permintaan GET tidak memiliki semantik yang ditentukan; mengirim badan muatan pada permintaan GET dapat menyebabkan beberapa implementasi yang ada untuk menolak permintaan." Jadi itu masih bukan ide yang bagus jika bisa dihindari.
fastcatch
290

Meskipun Anda dapat melakukannya, sejauh itu tidak secara eksplisit dikecualikan oleh spesifikasi HTTP, saya sarankan menghindarinya hanya karena orang tidak mengharapkan sesuatu berfungsi seperti itu. Ada banyak fase dalam rantai permintaan HTTP dan sementara mereka "sebagian besar" sesuai dengan spesifikasi HTTP, satu-satunya hal yang Anda yakini adalah mereka akan berperilaku seperti yang biasa digunakan oleh browser web. (Saya memikirkan hal-hal seperti proksi transparan, akselerator, toolkit A / V, dll.)

Ini adalah semangat di balik Prinsip Robustness yang secara kasar "menjadi liberal dalam apa yang Anda terima, dan konservatif dalam apa yang Anda kirim", Anda tidak ingin memaksakan batasan spesifikasi tanpa alasan yang kuat.

Namun, jika Anda memiliki alasan yang bagus, lakukanlah.

caskey
sumber
229
Prinsip Robustness cacat. Jika Anda liberal dalam apa yang Anda terima, Anda akan mendapatkan omong kosong, jika Anda berhasil dalam hal adopsi, hanya karena Anda menerima omong kosong. Itu akan membuat Anda lebih sulit untuk mengembangkan antarmuka Anda. Lihat saja HTML. Itulah prinsip reboustness dalam aksi.
Eugene Beresovsky
28
Saya pikir keberhasilan dan keluasan adopsi (dan penyalahgunaan) protokol berbicara dengan nilai dari prinsip ketahanan.
caskey
39
Pernahkah Anda mencoba parsing HTML nyata? Tidak mungkin untuk mengimplementasikannya sendiri, itu sebabnya hampir semua orang - termasuk pemain yang sangat besar seperti Google (Chrome) dan Apple (Safari), tidak melakukannya tetapi mengandalkan implementasi yang ada (pada akhirnya mereka semua bergantung pada KHTML KDE). Penggunaan kembali itu tentu saja menyenangkan, tetapi apakah Anda sudah mencoba menampilkan html dalam aplikasi .net? Ini adalah mimpi buruk, karena Anda harus menyematkan komponen IE (atau yang tidak dikelola) yang tidak dikelola, dengan masalah dan kerusakannya, atau Anda menggunakan komponen yang dikelola (pada codeplex) yang tersedia yang bahkan tidak memungkinkan Anda memilih teks.
Eugene Beresovsky
6
Tidak hanya spesifikasi HTTP yang memungkinkan data tubuh dengan permintaan GET, tetapi ini juga merupakan praktik umum: _search API mesin ElasticSearch yang populer merekomendasikan permintaan GET dengan kueri yang terlampir di badan JSON. Sebagai konsesi untuk implementasi klien HTTP yang tidak lengkap, ini juga memungkinkan permintaan POST di sini.
Christian Pietsch
4
@ChristianPietsch, itu adalah praktik umum hari ini. Empat tahun yang lalu tidak. Sementara spesifikasi secara eksplisit memungkinkan klien untuk secara opsional memasukkan (MUNGKIN) suatu entitas dalam permintaan (bagian 7), arti dari MUNGKIN didefinisikan dalam RFC2119 dan server proxy (jelek) dapat menjadi spesifikasi yang kompatibel saat menanggalkan entitas dalam permintaan GET, khusus selama tidak macet, ia dapat memberikan 'fungsionalitas yang dikurangi' dengan meneruskan header permintaan dan bukan entitas yang disertakan. Demikian juga ada sejumlah aturan tentang perubahan versi apa yang HARUS / MUNGKIN / HARUS dilakukan saat proksi di antara berbagai tingkat protokol.
caskey
151

Anda mungkin akan menemui masalah jika mencoba memanfaatkan caching. Proxy tidak akan mencari di badan GET untuk melihat apakah parameter berdampak pada respons.

Darrel Miller
sumber
10
Menggunakan ETag / Last-Modified header fields membantu dengan cara ini: ketika "GET bersyarat" digunakan, proksi / cache dapat bertindak atas informasi ini.
jldupont
2
@jldupont Tembolok menggunakan keberadaan validator untuk mengetahui apakah respons basi dapat divalidasi ulang, namun, mereka tidak digunakan sebagai bagian dari kunci cache primer atau sekunder.
Darrel Miller
Anda bisa memperbaikinya dengan checksum tubuh di parameter kueri
Adrian
73

Baik restclient maupun REST console tidak mendukung ini tetapi curl dapat.

The spesifikasi HTTP mengatakan di bagian 4.3

Badan pesan TIDAK HARUS dimasukkan dalam permintaan jika spesifikasi metode permintaan (bagian 5.1.1) tidak memungkinkan pengiriman badan hukum dalam permintaan.

Bagian 5.1.1 mengarahkan kita ke bagian 9.x untuk berbagai metode. Tak satu pun dari mereka yang secara eksplisit melarang penyertaan badan pesan. Namun...

Bagian 5.2 mengatakan

Sumber daya persis yang diidentifikasi oleh permintaan Internet ditentukan dengan memeriksa bidang Request-URI dan header Host.

dan Bagian 9.3 mengatakan

Metode GET berarti mengambil informasi apa pun (dalam bentuk entitas) yang diidentifikasi oleh Request-URI.

Yang bersama-sama menyarankan bahwa saat memproses permintaan GET, server tidak diharuskan untuk memeriksa hal lain selain bidang header Permintaan-URI dan Host.

Singkatnya, spesifikasi HTTP tidak mencegah Anda mengirim pesan-pesan dengan GET tetapi ada ambiguitas yang cukup sehingga tidak akan mengejutkan saya jika tidak didukung oleh semua server.

Dave Durbin
sumber
2
Paw juga memiliki opsi untuk mendukung permintaan GET dengan badan tetapi harus diaktifkan dalam pengaturan.
s.Daniel
"Metode GET berarti mengambil informasi apa pun (dalam bentuk entitas) yang diidentifikasi oleh Request-URI." Lalu, apakah secara teknis ilegal / salah memiliki titik akhir GET yang mendapatkan semua entitas? Misalnya GET /contacts/100/addressesmengembalikan koleksi alamat untuk orang dengan id=100.
Josh M.
Pustaka Java yang dijamin untuk pengujian API REST tidak mendukung permintaan GET dengan badan. Apache HttpClient juga tidak mendukungnya.
Paulo Merson
Django juga mendukung penguraian tubuh GET
Bruno Finger
60

Elasticsearch menerima permintaan GET dengan badan. Bahkan sepertinya inilah cara yang lebih disukai: panduan Elasticsearch

Beberapa perpustakaan klien (seperti driver Ruby) dapat mencatat perintah cry ke stdout dalam mode pengembangan dan menggunakan sintaksis ini secara ekstensif.

selamat
sumber
5
Bertanya-tanya mengapa Elasticsearch memungkinkan ini. Itu berarti permintaan ini untuk menghitung semua dokumen dengan muatan ke permintaan GET curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' setara dengan memasukkan muatan sebagai sourceparam: curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
arun
40
Kueri kompleks dapat mencapai panjang maks header http.
s.Daniel
11
Itu membaca dokumentasi elasticsearch yang membawa saya ke pertanyaan ini karena saya pikir itu dianggap praktik yang buruk untuk memasukkan tubuh
PatrickWalker
1
Bahkan tidak perlu menjadi query yang kompleks. Bahkan sebuah scroll sederhana dapat mengembalikan scroll_id yang sangat panjang (dalam sebuah cluster dengan banyak pecahan), yang akan menyebabkan overrunning panjang url maksimum jika ditambahkan di sana.
Brent Hronik
11
Elasticsearch mendukung permintaan yang sama menggunakan POST. Mereka hanya memilih untuk mengizinkan suatu badan dalam GET karena mereka merasa GET lebih benar secara semantik daripada POST ketika datang ke query data. Lucu sekali kalau Elasticsearch disebut-sebut begitu banyak di utas ini. Saya tidak akan menggunakan satu contoh (meskipun dari produk yang populer) sebagai alasan untuk mengikuti praktik ini.
DSO
33

Apa yang Anda coba capai telah dilakukan sejak lama dengan metode yang jauh lebih umum, dan yang tidak bergantung pada menggunakan muatan dengan GET.

Anda hanya dapat membangun media pencarian spesifik Anda, atau jika Anda ingin lebih tenang, gunakan sesuatu seperti OpenSearch, dan POST permintaan ke URI yang diinstruksikan oleh server, katakan / cari. Server kemudian dapat menghasilkan hasil pencarian atau membangun URI akhir dan mengarahkan kembali menggunakan 303.

Ini memiliki keuntungan mengikuti metode PRG tradisional, membantu perantara cache cache hasil, dll.

Yang mengatakan, URI dikodekan pula untuk apa pun yang bukan ASCII, dan begitu pula aplikasi / x-www-form-urlencoded dan multipart / form-data. Saya sarankan menggunakan ini daripada membuat format json kustom lain jika niat Anda adalah untuk mendukung skenario ReSTful.

SerialSeb
sumber
4
Anda cukup membuat mediatype pencarian spesifik Anda. Bisakah Anda menguraikannya?
Piotr Dobrogost
2
Dengan itu saya mengatakan bahwa Anda dapat membuat jenis media yang disebut application / vnd.myCompany.search + json yang akan berisi jenis templat pencarian yang Anda ingin klien terbitkan, dan klien kemudian dapat mengirimkannya sebagai POST. Seperti yang saya soroti, sudah ada jenis media untuk itu dan itu disebut OpenSearch, menggunakan kembali jenis media yang ada harus dipilih daripada rute kustom ketika Anda dapat menerapkan skenario Anda dengan standar yang ada.
SerialSeb
14
Itu pintar, tetapi terlalu rumit, dan tidak efisien. Sekarang Anda harus mengirim POST dengan kriteria pencarian Anda, dapatkan URI sebagai respons balik dari POST Anda, lalu kirim GET dengan kriteria pencarian URI ke server untuk mendapatkan GET kriteria dan kirim hasilnya kembali kepada Anda. (Kecuali bahwa memasukkan URI dalam URI secara teknis tidak mungkin karena Anda tidak dapat mengirim sesuatu yang bisa mencapai 255 karakter dalam sesuatu yang bisa tidak lebih dari 255 karakter - jadi Anda harus menggunakan pengidentifikasi parsial dan server Anda kemudian perlu tahu cara menyelesaikan URI untuk kriteria pencarian
POSTed Anda
30

Anda dapat mengirim GET dengan badan atau mengirim POST dan menyerah RESTish religiositas (tidak terlalu buruk, 5 tahun yang lalu hanya ada satu anggota dari iman itu - komentarnya terkait di atas).

Tidak ada keputusan besar, tetapi mengirim badan GET dapat mencegah masalah untuk beberapa klien - dan beberapa server.

Melakukan POST mungkin memiliki hambatan dengan beberapa kerangka kerja RESTish.

Julian Reschke menyarankan di atas menggunakan tajuk HTTP non-standar seperti "SEARCH" yang bisa menjadi solusi yang elegan, kecuali bahwa kemungkinannya lebih kecil untuk didukung.

Mungkin paling produktif untuk mendaftar klien yang dapat dan tidak dapat melakukan masing-masing hal di atas.

Klien yang tidak dapat mengirim GET dengan tubuh (yang saya tahu):

  • XmlHTTPRequest Fiddler

Klien yang dapat mengirim GET dengan tubuh:

  • sebagian besar browser

Server & pustaka yang dapat mengambil tubuh dari GET:

  • Apache
  • PHP

Server (dan proksi) yang melepaskan tubuh dari GET:

  • ?
fijiaaron
sumber
2
Squid 3.1.6 juga menghapus GET badan ketika Content-Length adalah 0 atau tidak diatur, dan sebaliknya mengirim kembali HTTP 411 Panjang Diperlukan meskipun panjangnya diatur
rkok
2
Fiddler akan, tetapi itu memperingatkan Anda.
toddmo
Apakah Anda mengatakan bahwa suatu SEARCHmetode mungkin akan pecah? Jika proksi tidak memahami metode, mereka diharapkan untuk melewatinya, jadi saya tidak terlalu yakin mengapa Anda berpikir itu akan merusak apa pun ...
Alexis Wilke
22

Saya mengajukan pertanyaan ini ke WET IETF HTTP. Komentar dari Roy Fielding (penulis http / 1.1 dokumen pada tahun 1998) adalah itu

"... sebuah implementasi akan rusak untuk melakukan apa saja selain mengurai dan membuang tubuh itu jika diterima"

Status RFC 7213 (HTTPbis):

"Muatan dalam pesan permintaan GET tidak memiliki semantik yang ditentukan;"

Tampaknya jelas sekarang bahwa maksudnya adalah bahwa makna semantik pada badan permintaan GET dilarang, yang berarti bahwa badan permintaan tidak dapat digunakan untuk mempengaruhi hasilnya.

Ada proksi di luar sana yang pasti akan merusak permintaan Anda dengan berbagai cara jika Anda menyertakan sebuah badan di GET.

Jadi secara ringkas, jangan lakukan itu.

Adrien
sumber
21

Server mana yang akan mengabaikannya? - fijiaaron 30 Agustus '12 pada 21:27

Google misalnya melakukan lebih buruk daripada mengabaikannya, itu akan menganggapnya sebagai kesalahan !

Cobalah sendiri dengan netcat sederhana:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(konten 1234 diikuti oleh CR-LF, sehingga totalnya adalah 6 byte)

dan Anda akan mendapatkan:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

Anda juga mendapatkan 400 Permintaan Buruk dari Bing, Apple, dll ... yang dilayani oleh AkamaiGhost.

Jadi saya tidak akan menyarankan menggunakan permintaan GET dengan entitas tubuh.

pengguna941239
sumber
65
Contoh ini tidak ada gunanya karena biasanya ketika orang akan menambahkan tubuh ke GETpermintaan, itu karena server kustom mereka dapat menanganinya. Pertanyaannya adalah apakah "bagian bergerak" lainnya (browser, cache, dll) akan berfungsi dengan baik.
Pacerier
6
Ini adalah permintaan yang buruk karena muatan Anda tidak diharapkan (atau masuk akal) untuk GET titik akhir tertentu - tidak ada hubungannya dengan penggunaan GETdalam kasus umum. Payload acak dapat memecahkan POSTdengan mudah, dan mengembalikan yang sama 400 Bad Request, jika konten tidak dalam format yang masuk akal dalam konteks permintaan spesifik.
Nobar
Dan tidak hanya pada titik akhir itu secara keseluruhan, tetapi lebih pada URL spesifik itu .
Lawrence Dol
1
Ini tidak relevan karena hanya implementasi server Google di URL itu. Jadi tidak masuk akal untuk pertanyaan
Joel Duckworth
bagi saya itu berguna, karena saya mencoba menggunakan fungsi firebase dengan permintaan + tubuh, dan kesalahan ini bisa sangat samar dan sulit dimengerti.
scrimau
19

Dari RFC 2616, bagian 4.3 , "Badan Pesan":

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.

Artinya, server harus selalu membaca badan permintaan yang disediakan dari jaringan (periksa Content-Length atau membaca badan yang terpotong, dll). Juga, proksi harus meneruskan badan permintaan yang mereka terima. Kemudian, jika RFC mendefinisikan semantik untuk tubuh untuk metode yang diberikan, server benar-benar dapat menggunakan tubuh permintaan dalam menghasilkan respons. Namun, jika RFC tidak mendefinisikan semantik untuk tubuh, maka server harus mengabaikannya.

Ini sesuai dengan kutipan dari Fielding di atas.

Bagian 9.3 , "GET", menjelaskan semantik metode GET, dan tidak menyebutkan badan permintaan. Oleh karena itu, server harus mengabaikan badan permintaan apa pun yang diterimanya atas permintaan GET.

izrik
sumber
Bagian 9.5 , "POST", juga tidak menyebutkan badan permintaan, jadi logika ini cacat.
CarLuva
9
@CarLuva Bagian POST mengatakan "Metode POST digunakan untuk meminta server asal menerima entitas terlampir ..." Bagian badan entitas mengatakan "Badan entitas diperoleh dari badan pesan ..." Oleh karena itu, Bagian POST memang menyebutkan badan pesan, meskipun secara tidak langsung dengan merujuk badan entitas yang dibawa oleh badan pesan dari permintaan POST.
frederickf
9

Menurut XMLHttpRequest, itu tidak valid. Dari standar :

4.5.6 send()Metode

client . send([body = null])

Memulai permintaan. Argumen opsional menyediakan badan permintaan. Argumen diabaikan jika metode permintaan adalah GETatau HEAD.

Melempar InvalidStateErrorpengecualian jika salah satu negara tidak dibuka atau send()bendera ditetapkan.

The Metode harus menjalankan langkah-langkah ini:send(body)

  1. Jika status tidak dibuka , berikan InvalidStateErrorpengecualian.
  2. Jika send()bendera diatur, lempar InvalidStateErrorpengecualian.
  3. Jika metode permintaan adalah GETatau HEAD, setel badan ke nol.
  4. Jika badan adalah nol, lanjutkan ke langkah berikutnya.

Meskipun, saya tidak berpikir itu harus karena permintaan GET mungkin memerlukan konten tubuh besar.

Jadi, jika Anda mengandalkan XMLHttpRequest dari browser, kemungkinan itu tidak akan berfungsi.

Rafael Sales
sumber
1
downvoted karena fakta bahwa XMLHttpRequest adalah implementasi. Ini mungkin tidak mencerminkan spesifikasi aktual yang seharusnya diterapkan.
floum
10
Downvote di atas salah, jika beberapa implementasi tidak mendukung pengiriman body dengan GET, maka itu mungkin menjadi alasan untuk tidak melakukannya, terlepas dari spesifikasinya. Saya benar-benar mengalami masalah yang tepat ini dalam produk lintas-platform yang saya kerjakan - hanya platform yang menggunakan XMLHttpRequest gagal mengirim get.
pjcard
8

Jika Anda benar-benar ingin mengirim isi JSON / XML ke aplikasi web, satu-satunya tempat yang masuk akal untuk meletakkan data Anda adalah string kueri yang dikodekan dengan RFC4648: Pangkalan 64 Pengkodean dengan URL dan Nama File Alfabet yang Aman . Tentu saja Anda bisa urlencode JSON dan meletakkannya di nilai param URL, tetapi Base64 memberikan hasil yang lebih kecil Ingatlah bahwa ada batasan ukuran URL, lihat Berapa panjang maksimum URL di berbagai browser? .

Anda mungkin berpikir bahwa =karakter padding Base64 mungkin buruk untuk nilai param URL, namun sepertinya tidak - lihat diskusi ini: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . Namun Anda tidak boleh memasukkan data yang dikodekan tanpa nama param karena string yang dikodekan dengan padding akan ditafsirkan sebagai kunci param dengan nilai kosong. Saya akan menggunakan sesuatu seperti ?_b64=<encodeddata>.

gertas
sumber
Saya pikir ini adalah ide yang sangat buruk :) Tetapi jika saya melakukan sesuatu seperti ini, saya akan menggunakan header HTTP khusus (dan pastikan bahwa saya selalu mengirim kembali Vary: dalam respon).
Evert
Buruk atau tidak tapi bisa dilakukan :) Dengan data dalam header ada masalah yang sama dengan ukuran data, lihat stackoverflow.com/questions/686217/… . Namun terima kasih telah menyebutkan Varytajuk, saya tidak menyadari potensi sebenarnya.
gertas
6

Saya tidak akan menyarankan ini, itu bertentangan dengan praktik standar, dan tidak menawarkan banyak imbalan. Anda ingin menjaga isi konten, bukan opsi.

cloudhead
sumber
5

Bagaimana dengan header yang disandikan base64 yang tidak sesuai? "SOMETHINGAPP-PARAMS: sdfSD45fdg45 / aS"

Pembatasan panjang hm. Tidak bisakah Anda membuat penanganan POST Anda membedakan antara artinya? Jika Anda ingin parameter sederhana seperti penyortiran, saya tidak melihat mengapa ini akan menjadi masalah. Saya kira pasti Anda khawatir tentang hal itu.

chaz
sumber
Anda dapat mengirim parameter apa pun yang Anda inginkan dengan x-awalan, batas apa pun pada panjang header sepenuhnya akan menjadi batas server sewenang-wenang.
Chris Marisic
4

Saya kesal karena REST sebagai protokol tidak mendukung OOP dan Getmetode adalah bukti. Sebagai solusi, Anda bisa membuat serial DTO ke JSON dan membuat string kueri. Di sisi server Anda akan dapat membatalkan deserialisasi string kueri ke DTO.

Lihatlah:

Pendekatan berbasis pesan dapat membantu Anda memecahkan batasan Dapatkan metode. Anda dapat mengirim DTO apa pun dengan badan permintaan

Kerangka kerja layanan web Nelibur menyediakan fungsionalitas yang dapat Anda gunakan

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D
GSerjo
sumber
8
Anda hanya harus menggunakan POST. Jika ada nama metode di url, Anda melanggar desain sisanya. Ini adalah RPC, gunakan POST.
Evert
3
Saya tidak berpikir itu masalah besar, kami memiliki lebih banyak masalah selama pengembangan dengan url ISTIRAHAT (yaitu pesanan / 1). Bagi saya, ada yang salah dengan metode Get, itu tidak kompatibel dengan OOP. Dan siapa yang peduli bagaimana bentuk urlnya :) Tapi dengan pendekatan berbasis pesan kita dapat membuat antarmuka jarak jauh yang stabil dan itu sangat penting. PS itu bukan RPC, itu berbasis pesan
GSerjo
3
Saya pikir Anda kehilangan inti dari REST. Ketika Anda mengatakan, siapa yang peduli seperti apa url itu, well REST peduli, banyak. Dan mengapa REST kompatibel dengan OOP?
shmish111
Tidak, saya tidak melihat sedikit lebih jauh
GSerjo
4

Misalnya, ini berfungsi dengan Curl, Apache dan PHP.

File PHP:

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

Perintah konsol:

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

Keluaran:

GET
{"the": "body"}
mnv
sumber
Eksperimen yang menyenangkan! PHP hanya akan membaca$_POST ketika badan dikirim dengan permintaan POST dan application/x-www-form-urlencoded. Itu berarti tubuh diabaikan dalam GETpermintaan. Dalam hal ini: $_GETdan bagaimanapun $_POSTjuga sangat menyesatkan pada saat ini. Jadi gunakan lebih baikphp://input
Martin Muzatko
3

IMHO Anda bisa mengirim yang JSONdisandikan (mis. encodeURIComponent) Di URL, dengan cara ini Anda tidak melanggar HTTPspesifikasi dan membawa Anda JSONke server.

EthraZa
sumber
28
ya tapi masalah utamanya adalah batas panjangnya, bagaimana kita menghadapinya?
Sebas
2

Anda memiliki daftar opsi yang jauh lebih baik daripada menggunakan badan permintaan dengan GET.

Mari kita asumsikan Anda memiliki kategori dan item untuk setiap kategori. Keduanya harus diidentifikasi oleh id ("catid" / "itemid" untuk kepentingan contoh ini). Anda ingin mengurutkan berdasarkan "sortby" parameter lain dalam "urutan" tertentu. Anda ingin memberikan parameter untuk "sortby" dan "order":

Kamu bisa:

  1. Gunakan string kueri, mis example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Gunakan mod_rewrite (atau serupa) untuk jalur: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. Gunakan tajuk HTTP terpisah yang Anda berikan dengan permintaan
  4. Gunakan metode yang berbeda, misalnya POST, untuk mengambil sumber daya.

Semua memiliki kelemahan, tetapi jauh lebih baik daripada menggunakan GET dengan tubuh.

Xenonite
sumber
0

Bahkan jika alat populer menggunakan ini, seperti yang sering dikutip di halaman ini, saya pikir itu masih ide yang buruk, terlalu eksotis, meskipun tidak dilarang oleh spek.

Banyak infrastruktur perantara mungkin menolak permintaan semacam itu.

Dengan contoh, melupakan menggunakan beberapa CDN tersedia di depan situs web Anda, seperti ini satu :

Jika GETpermintaan pemirsa menyertakan sebuah badan, CloudFront mengembalikan kode status HTTP 403 (Terlarang) ke pemirsa.

Dan ya, perpustakaan klien Anda mungkin juga tidak mendukung memancarkan permintaan seperti itu, seperti yang dilaporkan dalam komentar ini .

Frédéric
sumber
0

Saya menggunakan RestTemplate kerangka Spring di program klien saya dan, di sisi server, saya mendefinisikan permintaan GET dengan tubuh Json. Tujuan utama saya sama dengan Anda: ketika permintaan memiliki banyak parameter, menempatkannya di tubuh tampak lebih rapi daripada menempatkannya di string URI yang berkepanjangan. Iya?

Tapi, sayangnya, itu tidak berhasil! Sisi server melemparkan pengecualian berikut:

org.springframework.http.converter.HttpMessageNotReadableException: Badan permintaan yang diperlukan tidak ada ...

Tapi saya cukup yakin badan pesan disediakan dengan benar oleh kode klien saya, jadi apa yang salah?

Saya menelusuri metode RestTemplate.exchange () dan menemukan yang berikut:

// SimpleClientHttpRequestFactory.class
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
    ...
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        ...
        if (!"POST".equals(httpMethod) && !"PUT".equals(httpMethod) && !"PATCH".equals(httpMethod) && !"DELETE".equals(httpMethod)) {
            connection.setDoOutput(false);
        } else {
            connection.setDoOutput(true);
        }
        ...
    }
}

// SimpleBufferingClientHttpRequest.class
final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest {
    ...
    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        ...
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }
        ...
    }
}

Harap perhatikan bahwa dalam metode executeInternal (), argumen input 'bufferedOutput' berisi isi pesan yang disediakan oleh kode saya. Saya melihatnya melalui debugger.

Namun, karena prepoconnection (), getDoOutput () dalam executeInternal () selalu mengembalikan false yang, pada gilirannya, membuat bufferedOutput benar-benar diabaikan! Itu tidak disalin ke aliran output.

Akibatnya, program server saya tidak menerima isi pesan dan melemparkan pengecualian itu.

Ini adalah contoh tentang kerangka RestTemplate dari Spring. Intinya adalah bahwa, bahkan jika badan pesan tidak lagi dilarang oleh spesifikasi HTTP, beberapa pustaka atau kerangka kerja klien atau server mungkin masih mematuhi spesifikasi lama dan menolak isi pesan dari permintaan GET.

Zhou
sumber
Anda tidak membaca spesifikasi atau komentar di sini dengan benar. Klien dan server menjatuhkan tubuh permintaan adalah dalam spec. Jangan gunakan badan permintaan GET.
Evert
@Evert Saya tidak membaca komentar dengan benar atau Anda tidak? :) Jika Anda gulir ke jawaban Paul Morgan (jawaban atas memukul) dan membaca komentar dengan hati-hati, Anda akan menemukan ini: "RFC2616 yang dirujuk sebagai" HTTP / 1.1 spec "sekarang sudah usang. Pada 2014 itu digantikan oleh RFCs 7230-7237. Kutipan "badan pesan HARUS diabaikan ketika menangani permintaan" telah dihapus. Sekarang hanya "Membingkai pesan pesan tidak tergantung pada metode semantik, bahkan jika metode tersebut tidak menentukan penggunaan apa pun untuk badan pesan ... "
Zhou
@Balik Lagi pula, saya menggunakan utilitas pengujian REST "yakinlah" untuk menguji backend Spring-boot saya. Kedua sisi server yang terjamin dan Spring-boot menyimpan Json body untuk permintaan GET! Hanya RestTemplate Sping-framework yang menghapus tubuh dari permintaan GET, jadi Spring-boot, yakinlah dan RestTemplate, yang mana / salah?
Zhou
@Belakang Terakhir tetapi tidak menyewa, saya tidak mendesak orang untuk menggunakan tubuh dalam permintaan GET, sebaliknya, saya menyarankan TIDAK melakukan itu dengan menganalisis kode sumber RestTemplate kerangka kerja Sping, jadi mengapa Anda memilih-pilih saya menjawab?
Zhou
Saya tidak mencatat jawaban Anda. Aku hanya menjelaskan bahwa setiap pelaksanaan HTTP request menjatuhkan GET adalah di spec.
Evert