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?
Jawaban:
Komentar Roy Fielding tentang memasukkan badan dengan permintaan GET .
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 :
Dan deskripsi metode GET dalam spec HTTP / 1.1, bagian 9.3 :
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
sumber
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.
sumber
Anda mungkin akan menemui masalah jika mencoba memanfaatkan caching. Proxy tidak akan mencari di badan GET untuk melihat apakah parameter berdampak pada respons.
sumber
Baik restclient maupun REST console tidak mendukung ini tetapi curl dapat.
The spesifikasi HTTP mengatakan di bagian 4.3
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
dan Bagian 9.3 mengatakan
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.
sumber
GET /contacts/100/addresses
mengembalikan koleksi alamat untuk orang denganid=100
.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.
sumber
curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'
setara dengan memasukkan muatan sebagaisource
param:curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
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.
sumber
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):
Klien yang dapat mengirim GET dengan tubuh:
Server & pustaka yang dapat mengambil tubuh dari GET:
Server (dan proksi) yang melepaskan tubuh dari GET:
sumber
SEARCH
metode 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 ...Saya mengajukan pertanyaan ini ke WET IETF HTTP. Komentar dari Roy Fielding (penulis http / 1.1 dokumen pada tahun 1998) adalah itu
Status RFC 7213 (HTTPbis):
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.
sumber
Google misalnya melakukan lebih buruk daripada mengabaikannya, itu akan menganggapnya sebagai kesalahan !
Cobalah sendiri dengan netcat sederhana:
(konten 1234 diikuti oleh CR-LF, sehingga totalnya adalah 6 byte)
dan Anda akan mendapatkan:
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.
sumber
GET
permintaan, itu karena server kustom mereka dapat menanganinya. Pertanyaannya adalah apakah "bagian bergerak" lainnya (browser, cache, dll) akan berfungsi dengan baik.GET
titik akhir tertentu - tidak ada hubungannya dengan penggunaanGET
dalam kasus umum. Payload acak dapat memecahkanPOST
dengan mudah, dan mengembalikan yang sama400 Bad Request
, jika konten tidak dalam format yang masuk akal dalam konteks permintaan spesifik.Dari RFC 2616, bagian 4.3 , "Badan Pesan":
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.
sumber
Menurut XMLHttpRequest, itu tidak valid. Dari standar :
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.
sumber
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>
.sumber
Vary
tajuk, saya tidak menyadari potensi sebenarnya.Saya tidak akan menyarankan ini, itu bertentangan dengan praktik standar, dan tidak menawarkan banyak imbalan. Anda ingin menjaga isi konten, bukan opsi.
sumber
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.
sumber
x-
awalan, batas apa pun pada panjang header sepenuhnya akan menjadi batas server sewenang-wenang.Saya kesal karena REST sebagai protokol tidak mendukung OOP dan
Get
metode 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
sumber
Misalnya, ini berfungsi dengan Curl, Apache dan PHP.
File PHP:
Perintah konsol:
Keluaran:
sumber
$_POST
ketika badan dikirim dengan permintaan POST danapplication/x-www-form-urlencoded
. Itu berarti tubuh diabaikan dalamGET
permintaan. Dalam hal ini:$_GET
dan bagaimanapun$_POST
juga sangat menyesatkan pada saat ini. Jadi gunakan lebih baikphp://input
IMHO Anda bisa mengirim yang
JSON
disandikan (mis.encodeURIComponent
) DiURL
, dengan cara ini Anda tidak melanggarHTTP
spesifikasi dan membawa AndaJSON
ke server.sumber
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:
example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
example.com/category/{catid}/item/{itemid}/{sortby}/{order}
Semua memiliki kelemahan, tetapi jauh lebih baik daripada menggunakan GET dengan tubuh.
sumber
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 :
Dan ya, perpustakaan klien Anda mungkin juga tidak mendukung memancarkan permintaan seperti itu, seperti yang dilaporkan dalam komentar ini .
sumber
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:
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.
sumber