İstek gövdesi ile HTTP GET


2110

Uygulamamız için yeni bir RESTful web hizmeti geliştiriyorum.

Belirli varlıklar için bir GET yaparken müşteriler varlığın içeriğini isteyebilir. Bazı parametreler eklemek istiyorlarsa (örneğin, bir listeyi sıralamak gibi) bu parametreleri sorgu dizesine ekleyebilirler.

Alternatif olarak, insanların bu parametreleri istek gövdesinde belirleyebilmesini istiyorum. HTTP / 1.1 bunu açıkça yasaklıyor gibi görünmüyor. Bu, daha fazla bilgi belirtmelerine olanak tanır, karmaşık XML istekleri belirtmeyi kolaylaştırabilir.

Sorularım:

  • Bu tamamen iyi bir fikir mi?
  • HTTP istemcilerinin bir GET isteği içinde istek gövdelerini kullanma konusunda sorunları olacak mı?

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


552
Avantajı, XML veya JSON istek gövdelerinin kolayca gönderilmesine izin vermesidir, uzunluk sınırlaması yoktur ve kodlaması daha kolaydır (UTF-8).
Evert

29
Eğer peşinde olduğunuz şey istek gövdelerine izin veren güvenli ve idempotent bir yöntemse, ARAMA, PROPFIND ve REPORT'a bakmak isteyebilirsiniz. Elbette GET kullanmamak ve bir istek gövdesine sahip olmak önbelleği az ya da çok yener.
Julian Reschke

226
@fijiaaron: 3 yıl sonra ve o zamandan beri webservices yazma konusunda geniş deneyim kazandım. Temelde son birkaç yıldır yaptığım şey bu. Güvenle söyleyebilirim, bir GET isteğine bir gövde eklemek gerçekten çok kötü bir fikir. İlk iki cevap bir kaya gibi duruyor.
Evert

26
@Ellesedil: Basitçe söylemek gerekirse: POST üzerinden GET kullanmanın avantajları ne olursa olsun, HTTP'nin nasıl tasarlandığından dolayı var olur. Standardı bu şekilde ihlal ettiğinizde bu avantajlar artık mevcut değil. Bu nedenle GET + 'ı POST yerine bir istek gövdesi kullanmak için yalnızca bir neden kaldı: Estetik. Sağlam tasarımı estetikten ödün vermeyin.
Evert

7
Evert'in söylediklerinin altını çizmek için: "uzunluk sınırlaması yoktur". Sorgu parametrelerine sahip GET'iniz uzunluk kısıtlamasını (2048) kırıyorsa, sorgu dizesi bilgilerini bir json nesnesine, örneğin isteğin gövdesine koymak dışında başka bir seçenek yoktur.
Kieran Ryan

Yanıtlar:


1724

Roy Fielding'in GET isteği olan bir organı dahil etme hakkındaki yorumu .

Evet. Başka bir deyişle, herhangi bir HTTP istek iletisinin bir ileti gövdesi içermesine izin verilir ve bu nedenle iletileri bu düşünceyle ayrıştırması gerekir. Bununla birlikte, GET için sunucu semantiği, eğer varsa, bir gövdenin istek için anlamsal bir anlamı olmayacak şekilde sınırlandırılmıştır. Ayrıştırma ile ilgili gereksinimler, yöntem semantiği ile ilgili gereksinimlerden ayrıdır.

Yani, evet, bir vücudu GET ile gönderebilirsiniz ve hayır, bunu yapmak asla yararlı değildir.

Bu, teknik özellik bölümlere ayrıldıktan sonra tekrar işlenecek olan katmanlı HTTP / 1.1 tasarımının bir parçasıdır (devam eden çalışma).

.... Roy

Evet, GET ile bir istek gövdesi gönderebilirsiniz, ancak bunun bir anlamı olmamalıdır. Sunucuda ayrıştırarak ve içeriğine göre yanıtınızı değiştirerek bir anlam verirseniz , HTTP / 1.1 spesifikasyonu, bölüm 4.3'te bu öneriyi göz ardı ediyorsunuz :

[...] istek yöntemi, bir varlık-gövde için tanımlanmış anlambilim içermiyorsa, istek işlenirken ileti gövdesi göz ardı EDİLMELİDİR .

HTTP / 1.1 spesifikasyonu, bölüm 9.3'teki GET yönteminin açıklaması :

GET yöntemi, İstek URI'sı tarafından tanımlanan bilgileri ([...]) almak anlamına gelir.

istek gövdesinin, bir GET isteğindeki kaynağın tanımlamasının bir parçası olmadığını, yalnızca istek URI'sını belirtir.

Güncelleme "HTTP / 1.1 spec" olarak adlandırılan RFC2616 artık kullanılmamaktadır. 2014 yılında yerini RFC 7230-7237 aldı. Alıntı "ileti işlenirken ileti gövdesi yok sayılmalıdır" silindi. Şimdi sadece "İstek çerçeveleme yöntem semantiğinden bağımsızdır, yöntem bir ileti gövdesi için herhangi bir kullanım tanımlamasa bile" 2. tırnak "GET yöntemi, İstek-URI tarafından tanımlanmış her türlü bilgiyi almak anlamına gelir ... silindi. - Bir yorumdan


71
Önbellekleme / proxy oluşturma, kırılma olasılığınız en yüksek olan iki şeydir, evet. "Anlambilim", "diğer bileşenleri yapan insanların diğer bileşenlerin çalışmasını bekleyeceği şekilde" söylemenin başka bir yoludur. Anlambilimi ihlal ederseniz, insanların bu anlambilimi onurlandırmanızı bekleyen şeyler yazdığı yerlerde işlerin kırıldığını görme olasılığınız daha yüksektir.
Stuart P. Bentley

108
Elasticsearch, GET'te HTTP istek gövdelerini kullanan oldukça büyük bir üründür. Kılavuzlarına göre, bir HTTP isteğinin bir gövdeye sahip olup olmadığını desteklemesi gerekip gerekmediği tanımlanmamıştır. Şahsen bir GET istek gövdesini doldurmaktan rahatsız değilim, ancak farklı bir görüşe sahipler ve ne yaptıklarını bilmeleri gerekiyor. elastic.co/guide/en/elasticsearch/guide/current/...
GordonM

25
@Iwein GET istek organları vermek aslında spec ihlali değildir . HTTP / 1.1 , sunucuların gövdeyi yoksayması gerektiğini belirtir, ancak RFC 2119 , uygulayıcıların bunu yapmak için iyi bir nedenleri varsa "SHOULD" yan tümcelerini yoksaymasına izin verileceğini belirtir. Aksine, bir istemci yapar o GET gövdesi değiştirilerek varsayar eğer spesifikasyonları ihlal değil yanıtını değiştirin.
Emil Lundberg

107
"HTTP / 1.1 spec" olarak adlandırılan RFC2616 artık kullanılmamaktadır. 2014 yılında yerini RFC 7230-7237 aldı. "Alıntı isteği işlerken mesajı vücut göz ardı GEREKEN olmuştur" silindi . Sadece "şimdi nerede yöntem bir mesaj gövdesi için herhangi kullanımını tanımlamak olmasa bile talep mesajı çerçeveleme, yöntem semantik bağımsızdır 2 alıntı" " vasıta ne olursa olsun bilgi almak GET yöntemiyle Request-URI ile tanımlanır ... " oldu silindi . Yani, cevabı @Jarl düzenlemenizi öneririm
Artem Nakonechny

28
Eski bir iplik olduğunu biliyorum - tökezledim. @Artem Nakonechny teknik olarak doğru ama yeni Spec diyor "GET isteği ileti içinde bir yük yok semantik tanımlamıştır;. Talebini reddetmek için bazı mevcut uygulamaları neden olabilir GET isteği üzerine bir yük vücuda göndererek" Bu yüzden önlenebilirse hala iyi bir fikir değildir.
fastcatch

289

Eğer iken olabilir bunu insanların bu şekilde çalışmaya şeyler beklemeyin çünkü, açıkça HTTP spesifikasyonu tarafından engel teşkil etmez sürece, bunu kaçınarak öneriyoruz. Bir HTTP istek zincirinde birçok aşama vardır ve bunlar HTTP özelliğine "çoğunlukla" uymakla birlikte, emin olduğunuz tek şey, bunların web tarayıcıları tarafından geleneksel olarak kullanıldıklarıdır. (Şeffaf vekiller, hızlandırıcılar, A / V araç takımları vb. Şeyleri düşünüyorum.)

Bu, Sağlamlık İlkesi'nin arkasındaki ruhtur, kabaca "kabul ettiğiniz şeyde liberal olun ve gönderdiğiniz şeyde muhafazakar olun", bir şartnamenin sınırlarını iyi bir sebep olmaksızın zorlamak istemezsiniz.

Ancak, iyi bir nedeniniz varsa, bunun için gidin.


228
Sağlamlık Prensibi kusurludur. Eğer kabul ettiğiniz şeyde liberalseniz, evlat edinme konusunda herhangi bir başarınız varsa, sadece bok kabul ettiğiniz için bok alacaksınız. Bu, arayüzünüzü geliştirmenizi zorlaştıracaktır. HTML'ye bakın. Bu, eylemdeki yeniden yapılanma ilkesidir.
Eugene Beresovsky

27
Protokollerin benimsenmesinin (ve kötüye kullanılmasının) başarısı ve genişliği, sağlamlık ilkesinin değerine işaret ettiğini düşünüyorum.
caskey

39
Hiç gerçek HTML'yi ayrıştırmayı denediniz mi? Bunu kendiniz uygulamak mümkün değildir, bu yüzden neredeyse herkes - Google (Chrome) ve Apple (Safari) gibi gerçekten büyük oyuncular dahil, bunu yapmadı, ancak mevcut uygulamalara güvendi (sonunda hepsi KDE'nin KHTML'sine güvendi). Bu yeniden kullanım elbette güzel, ama bir .net uygulamasında html görüntülemeyi denediniz mi? Sorunları ve çökmeleri ile - yönetilmeyen - IE (veya benzeri) bir bileşen gömmeniz gerektiğinden veya metin seçmenize bile izin vermeyen kullanılabilir (codeplex üzerinde) yönetilen bileşeni kullandığınız için bir kabus.
Eugene Beresovsky

6
HTTP spesifikasyonu yalnızca GET isteği ile gövde verilerine izin vermekle kalmaz, aynı zamanda yaygın bir uygulamadır: Popüler Elastik Arama motorunun _search API'sı, bir JSON gövdesine eklenen sorgu ile GET isteklerini önerir. Eksik HTTP istemci uygulamaları için bir imtiyaz olarak, burada da POST isteklerine izin verir.
Christian Pietsch

3
@ChristianPietsch, bugün yaygın bir uygulamadır. Dört yıl önce değildi. Spec, bir istemcinin isteğe bağlı olarak bir varlığı isteğe (MAY) dahil etmesine izin verirken (bölüm 7), MAY'ın anlamı RFC2119'da tanımlanır ve (crappy) proxy sunucusu GET isteklerindeki varlıkları çıkarırken spesifik olarak uyumlu olabilir, özellikle çökmediği sürece, dahil edilen varlığı değil, istek başlıklarını ileterek 'sınırlı işlevsellik' sağlayabilir. Benzer şekilde, farklı protokol seviyeleri arasında proxy yaparken hangi sürüm değişikliklerinin YAPILMASI GEREKİR / MAYIS / YAPILMASI gerektiğine ilişkin bir dizi kural vardır.
caskey

151

Önbelleğe alma özelliğinden yararlanmaya çalışırsanız muhtemelen sorunlarla karşılaşırsınız. Proxy'ler, parametrelerin yanıt üzerinde bir etkisi olup olmadığını görmek için GET gövdesine bakmayacaktır.


10
ETag / Son Değiştirilmiş başlık alanlarının kullanılması bu şekilde yardımcı olur: "koşullu GET" kullanıldığında, proxy'ler / önbellekler bu bilgiler üzerinde etkili olabilir.
jldupont

2
@jldupont Önbellekler, eski bir yanıtın yeniden doğrulanıp onaylanamayacağını bilmek için doğrulayıcıların varlığını kullanır, ancak bunlar birincil veya ikincil önbellek anahtarının bir parçası olarak kullanılmaz.
Darrel Miller

Bunu bir sorgu parametresinde gövdenin bir sağlama toplamı ile düzeltebilirsiniz
Adrian Mayıs

73

Ne restclient ne de REST konsolu bunu desteklemez ancak curl bunu desteklemez.

HTTP şartname bölümünde 4.3 diyor

İstek yönteminin (bölüm 5.1.1) belirtimi, isteklerde varlık gövdesi gönderilmesine izin vermiyorsa, ileti gövdesi bir istekte BULUNMAMALIDIR.

Bölüm 5.1.1 , çeşitli yöntemler için bizi bölüm 9.x'e yönlendirir. Hiçbiri bir mesaj gövdesinin dahil edilmesini açıkça yasaklamamaktadır. Ancak...

Bölüm 5.2 diyor

İnternet isteği tarafından tanımlanan kesin kaynak, hem İstek-URI'sı hem de Ana Bilgisayar üstbilgisi alanı incelenerek belirlenir.

ve Bölüm 9.3 diyor ki

GET yöntemi, İstek-URI'si tarafından tanımlanan herhangi bir bilgiyi (varlık biçiminde) almak anlamına gelir.

Hangi birlikte bir GET isteği işlenirken, bir sunucu istek-URI ve ana bilgisayar üstbilgi alan başka bir şey incelemek için gerekli değildir öneririz .

Özetle, HTTP spesifikasyonu GET ile bir ileti gövdesi göndermenizi engellemez, ancak tüm sunucular tarafından desteklenmiyorsa beni şaşırtmayacak kadar belirsizlik vardır.


2
Paw'ın GET isteklerini gövdelerle destekleme seçeneği de vardır, ancak ayarlarda etkinleştirilmelidir.
s.Daniel

"GET yöntemi, İstek-URI tarafından tanımlanan herhangi bir bilginin (bir varlık biçiminde) alınması anlamına gelir." Peki, tüm varlıkları alan bir GET uç noktasına sahip olmak teknik olarak yasadışı / yanlış mı? Örn. GET /contacts/100/addressesİle birlikte bir adres koleksiyonu döndürür id=100.
Josh

REST API'lerini test etmek için güvenli Java kitaplığı, bir gövdeyle GET isteğini desteklemez. Apache HttpClient de desteklemiyor.
Paulo Merson

Django ayrıca bir GET vücut ayrıştırma destekler
Bruno Finger

60

Elasticsearch, bir kuruluşla GET isteklerini kabul eder. Hatta bu tercih edilen yol gibi görünüyor: Elasticsearch kılavuzu

Bazı istemci kitaplıkları (Ruby sürücüsü gibi) geliştirme modunda stdout'a cry komutunu kaydedebilir ve bu sözdizimini yoğun bir şekilde kullanır.


5
Elasticsearch'ün buna neden izin verdiğini merak ediyordum. Bu, bir GET isteğine yük içeren tüm belgeleri saymak için yapılan bu sorgunun curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' , yükü sourceparam olarak dahil etmeye eşdeğer olduğu anlamına gelir :curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
arun

40
Karmaşık sorgular http başlığı maksimum uzunluğuna vurabilir.
s.Daniel

11
Bir vücudu dahil
etmenin

1
Karmaşık bir sorgu olması bile gerekmez. Basit bir kaydırma bile çok uzun bir scroll_id döndürebilir (birçok parçalı bir kümede), bu da buraya eklenirse maksimum url uzunluğunu aşmaya neden olur.
Brent Hronik

11
Elasticsearch, POST kullanarak aynı isteği destekler. Yalnızca bir GET'teki bir gövdeye izin vermeyi seçtiler, çünkü veri sorgulama söz konusu olduğunda bir GET'in POST'den daha anlamsal olarak doğru olduğunu hissettiler. Bu konuya Elasticsearch'ün çok fazla değinmesi komik. Uygulamayı takip etmek için bir örneği (popüler bir üründen de olsa) kullanmam.
DSO

33

Ulaşmaya çalıştığınız şey, çok daha yaygın bir yöntemle ve GET ile bir yük kullanımına dayanmayan bir yöntemle uzun zamandır yapıldı.

Özel arama aralığınızı oluşturabilir veya daha RESTful olmak istiyorsanız, OpenSearch gibi bir şey kullanın ve sunucunun söylediği / arama gibi talimat verilen URI'ye POST isteği gönderin. Sunucu daha sonra arama sonucunu oluşturabilir veya son URI'yi oluşturabilir ve bir 303 kullanarak yeniden yönlendirebilir.

Bu, geleneksel PRG yöntemini takip etme avantajına sahiptir, önbellek aracılarının sonuçları önbelleğe almasına vb. Yardımcı olur.

Bununla birlikte, URI'ler ASCII olmayan herhangi bir şey için yine de kodlanır ve bu nedenle application / x-www-form-urlencoded ve multipart / form-data da öyle. Amacınız ReSTful senaryolarını desteklemekse, başka bir özel json formatı oluşturmak yerine bunu kullanmanızı tavsiye ederim.


4
Siz sadece özel arama MediaType inşa edebilirsiniz sen açar mısınız?
Piotr Dobrogost

2
Bununla, bir istemcinin yayınlamasını istediğiniz arama şablonu türünü içeren application / vnd.myCompany.search + json adlı bir medya türü oluşturabileceğinizi ve müşteri daha sonra bir POST olarak gönderebileceğinizi söylüyordum. Vurguladığım gibi, bunun için zaten bir medya türü var ve buna OpenSearch deniyor, senaryonuzu mevcut standartlarla uygulayabildiğiniz zaman mevcut bir medya türünün yeniden kullanılması özel rota üzerinden seçilmelidir.
SerialSeb

14
Bu zeki, ama aşırı karmaşık ve verimsiz. Şimdi arama ölçütlerinizle birlikte bir POST göndermeniz, POST'nuzdan bir yanıt olarak bir URI almanız ve daha sonra arama ölçütleri URI'sı olan bir GET'i sunucuya ölçütleri GET'e göndermeniz ve sonucu size geri göndermeniz gerekir. (Bir URI'ye bir URI eklemek teknik olarak imkansızdır, çünkü 255 karakterden fazla olmayan bir şey içinde 255 karaktere kadar bir şey gönderemezsiniz - bu nedenle kısmi bir tanımlayıcı ve sunucunuz kullanmanız gerekir.
POSTed

30

Bir bedenle bir GET gönderebilir veya bir POST gönderebilir ve RESTish dindarlığından vazgeçebilirsiniz (o kadar da kötü değil, 5 yıl önce bu inancın sadece bir üyesi vardı - yorumları yukarıda bağlantılı).

Büyük kararlar da yoktur, ancak bir GET gövdesi göndermek bazı istemciler ve bazı sunucular için sorunları önleyebilir.

POST yapmanın bazı RESTish çerçevelerinde engeller olabilir.

Julian Reschke yukarıda "SEARCH" gibi standart olmayan bir HTTP üstbilgisi kullanılmasını önerdi.

Yukarıdakilerin her birini yapabilen ve yapamayan müşterileri listelemek en verimli olabilir.

Vücut ile bir GET gönderemeyen müşteriler (bildiğim):

  • İstek Kemancı

Gövde ile bir GET gönderebilen müşteriler:

  • çoğu tarayıcı

Bir gövdeyi GET'ten alabilen sunucular ve kütüphaneler:

  • Apaçi
  • PHP

Bir gövdeyi GET'ten ayıran sunucular (ve proxy'ler):

  • ?

2
Squid 3.1.6, İçerik Uzunluğu 0 olduğunda veya ayarlanmadığında GET gövdelerini de şeritler ve aksi halde uzunluk ayarlanmış olsa bile gerekli bir HTTP 411 Uzunluğu geri gönderir
rkok

2
Kemancı yapacak, ama sizi uyarıyor.
toddmo

Bir SEARCHyöntemin muhtemelen yol boyunca ilerleyeceğini mi söylüyorsunuz ? Proxy'ler bir yöntemi anlamıyorlarsa, bu yöntemi olduğu gibi geçirmeleri beklenir, bu yüzden neden bir şeyi kıracağını düşündüğünüzden emin değilim ...
Alexis Wilke

22

Bu soruyu IETF HTTP WG'ye sordum. Roy Fielding'in (1998'deki http / 1.1 belgesinin yazarı) yorumu

“... bir uygulama, alındığı takdirde bu organı ayrıştırmak ve atmaktan başka bir şey yapamazdı”

RFC 7213 (HTTPbis) şunları belirtir:

"Bir GET istek mesajındaki bir yükün tanımlanmış bir anlam bilgisi yoktur;"

Niyetin GET istek organları üzerindeki anlamsal anlamın yasak olduğu açıktır, bu da istek organının sonucu etkilemek için kullanılamayacağı anlamına gelir.

GET'te bir gövde eklerseniz, isteğinizi kesinlikle çeşitli şekillerde kıracak proxy'ler var .

Özet olarak, yapma.


21

Hangi sunucu onu yoksayacak? - fijiaaron 30 '12, 21:27

Örneğin, Google bunu görmezden gelmekten daha kötü yapıyor, bir hata olarak kabul edecek !

Basit bir netcat ile kendiniz deneyin:

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

1234

(1234 içeriğinin ardından CR-LF gelir, bu nedenle toplam 6 bayttır)

ve alacaksınız:

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.

Ayrıca AkamaiGhost tarafından sunulan Bing, Apple, vb ... 400 Kötü İstek alırsınız.

Bu yüzden bir vücut varlığı ile GET isteklerini kullanmanızı tavsiye etmem.


65
Bu örnek anlamsızdır, çünkü genellikle insanlar GETisteklere gövde ekleyeceklerinde , bunun nedeni kendi özel sunucularının işleyebilmesidir. Dolayısıyla soru, diğer "hareketli parçaların" (tarayıcılar, önbellekler vb.) Düzgün çalışıp çalışmayacağıdır.
Pacerier

6
Bu kötü bir istektir, çünkü yükünüz GET belirli bir uç noktada için beklenmedik (veya mantıklı) değildir - GETgenel durumda kullanımıyla ilgisi yoktur . Rastgele bir yük , içerikler özel istek bağlamında anlamlı bir formatta olmasaydı POST, aynı derecede kolay bir şekilde kırılabilir ve aynı şekilde geri dönebilir 400 Bad Request.
nobar

Ve sadece bir bütün olarak bu uç noktada değil , belirli bir URL'de .
Lawrence Dol

1
Bu önemsizdir, çünkü bu URL'de yalnızca Google'ın sunucu uygulamasıdır. Bu soruya bir anlam ifade etmiyor
Joel Duckworth

benim için yararlı oldu, çünkü bir get request + body ile firebase fonksiyonlarını kullanmaya çalışıyordu ve bu hata çok şifreli ve anlaşılması zor olabilir.
scrimau

19

Gönderen RFC 2616, bölüm 4.3 , "Mesaj Gövdesi":

Bir sunucu, herhangi bir istek üzerine bir ileti gövdesini okumalı ve iletmelidir; istek yöntemi varlık gövdesi için tanımlanmış anlambilim içermiyorsa, istek işlenirken ileti gövdesi göz ardı EDİLMELİDİR.

Yani, sunucular her zaman ağdan sağlanan herhangi bir istek gövdesini okumalıdır (İçerik Uzunluğunu kontrol edin veya yığınlanmış bir gövde vb. Okuyun). Ayrıca, vekil sunucuların bu tür talep organlarını iletmeleri gerekir. Daha sonra, RFC, verilen yöntem için gövdeye ilişkin anlambilim tanımlarsa, sunucu aslında istek gövdesini bir yanıt oluştururken kullanabilir. RFC Ancak, gelmez vücut için anlambilim tanımlamak, sunucu bunu görmezden gerekir.

Bu, yukarıdaki Fielding'in alıntısı ile uyumludur.

Bölüm 9.3 , "GET", GET yönteminin anlambilimini açıklar ve istek kuruluşlarından bahsetmez. Bu nedenle, sunucu bir GET isteğinde aldığı istek gövdesini yok saymalıdır.


Kısım 9.5 , "POST", istek organlarından da bahsetmemektedir, bu nedenle bu mantık kusurludur.
CarLuva

9
@CarLuva POST bölümünde "POST yöntemi, kaynak sunucunun ekteki varlığı kabul etmesini istemek için kullanılır ..." Varlık gövdesi bölümünde "Varlık-gövde ileti gövdesinden alınır ..." Bu nedenle, POST bölümünde dolaylı olarak POST talebinin mesaj gövdesi tarafından taşınan varlık gövdesine atıfta bulunulsa da mesaj gövdesinden bahsedilir.
frederickf

9

XMLHttpRequest'e göre, geçerli değil. Gönderen standardı :

4.5.6 send()Yöntem

client . send([body = null])

İsteği başlatır. İsteğe bağlı argüman istek gövdesini sağlar. İstek yöntemi GETveya ise, bağımsız değişken yoksayılır HEAD.

Bir Atar InvalidStateErrorya devlet değilse istisna açılmış veya send()bayrak ayarlanır.

Yöntem şu adımları çalıştırmak gerekir:send(body)

  1. Durum açılmazsa , bir InvalidStateErroristisna atın .
  2. Eğer send()bayrak ayarlanırsa, bir atmak InvalidStateErroristisna.
  3. İstek yöntemi GETveya ise HEAD, gövdeyi null olarak ayarlayın .
  4. Eğer vücut null, bir sonraki adıma geçin.

Bununla birlikte, olması gerektiğini düşünmüyorum çünkü GET isteğinin büyük vücut içeriğine ihtiyacı olabilir.

Bu nedenle, bir tarayıcının XMLHttpRequest öğesine güveniyorsanız, muhtemelen çalışmaz.


1
XMLHttpRequest'in bir uygulama olması nedeniyle indirgenmiştir. Gerçekleştirmesi gereken gerçek özellikleri yansıtmayabilir.
18'de floum

10
Yukarıdaki downvote yanlıştır, eğer bazı uygulamalar bir GET ile bir gövdeyi göndermeyi desteklemiyorsa, bu özellik ne olursa olsun, bunu yapmamanın bir nedeni olabilir. Aslında tam olarak üzerinde çalıştığım bir çapraz platform ürün bu sorunla karşılaştı - sadece XMLHttpRequest kullanarak platform get göndermek için başarısız oldu.
pjcard

8

Gerçekten web uygulamasına cacheble JSON / XML gövdesi göndermek istiyorsanız, verilerinizi koymak için tek makul yer RFC4648 ile kodlanmış sorgu dizesi : URL ve Dosya Adı Güvenli Alfabesi ile Temel 64 Kodlama . Tabii ki sadece JSON urlencode ve put URL parametresi değerindedir, ancak Base64 daha küçük sonuç verir. URL boyutu kısıtlamaları olduğunu unutmayın, bkz . Farklı tarayıcılarda bir URL'nin maksimum uzunluğu nedir? .

Base64'ün dolgu =karakterinin URL'nin param değeri için kötü olabileceğini düşünebilirsiniz , ancak öyle görünmüyor - bu tartışmaya bakın: http://mail.python.org/pipermail/python-bugs-list/2007-Şubat/037195.html . Ancak, dolgulu kodlanmış dize boş değere sahip param anahtarı olarak yorumlanacağı için, param adı olmadan kodlanmış verileri koymamalısınız. Gibi bir şey kullanırdım ?_b64=<encodeddata>.


Bu oldukça kötü bir fikir olduğunu düşünüyorum :) Ama böyle bir şey yapsaydım, bunun yerine özel bir HTTP üstbilgisi kullanırdım (ve her zaman Vary: yanıt olarak geri gönderdiğimden emin olurum).
Evert

Kötü ya da değil ancak yapılabilir :) Üstbilgideki verilerde veri boyutu ile benzer bir sorun var, bkz. Stackoverflow.com/questions/686217/… . Ancak Varybaşlıktan bahsettiğiniz için teşekkürler , bunun gerçek potansiyelinin farkında değildim.
gertas

6

Bunu tavsiye etmem, standart uygulamalara aykırıdır ve karşılığında çok fazla şey sunmaz. Vücudu seçenekler için değil içerik için saklamak istiyorsunuz.


5

Uygun olmayan base64 kodlu üstbilgilere ne olacak? "SOMETHINGAPP-PARAMS: sdfSD45fdg45 / aS"

Uzunluk kısıtlamaları hm. POST işlemelerinizin anlamlarını ayırt etmesini sağlayamaz mısınız? Sıralama gibi basit parametreler istiyorsanız, bunun neden bir sorun olacağını anlamıyorum. Sanırım endişelendiğin kesinlik.


x-Önek ile istediğiniz parametreleri gönderebilirsiniz , üstbilgilerin uzunluğundaki herhangi bir sınır tamamen bir sunucunun keyfi sınırı olacaktır.
Chris Marisic

4

Protokol OOP desteklemiyor gibi REST üzgünüm ve Getyöntem kanıttır. Çözüm olarak, bir DTO'nuzu JSON'a serileştirebilir ve ardından bir sorgu dizesi oluşturabilirsiniz. Sunucu tarafında, sorgu dizesini DTO'nun serisini kaldırabilirsiniz.

Bir göz atın:

İleti tabanlı yaklaşım, yöntem kısıtlamasını almanızı çözmenize yardımcı olabilir. İstek gövdesinde olduğu gibi herhangi bir DTO gönderebilirsiniz

Nelibur web hizmeti çerçevesi kullanabileceğiniz işlevsellik sağlar

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

8
Sadece POST kullanmalısınız. URL'de bir yöntem adı varsa, temel dinlenme tasarımını ihlal edersiniz. Bu RPC, POST kullanın.
Evert

3
Bunun büyük bir anlaşma olduğunu düşünmüyorum, RESTful url (yani siparişler / 1) ile geliştirme sırasında daha fazla sorun yaşıyoruz. Bana gelince, Get yöntemiyle ilgili yanlış bir şey, OOP ile uyumsuz. Ve url'nin nasıl göründüğünü önemseyen :) Ama mesaj tabanlı yaklaşımla istikrarlı bir uzaktan arayüz oluşturabiliriz ve gerçekten önemlidir. PS, RPC değil, mesaj tabanlı
GSerjo

3
Bence REST'in tüm noktasını kaçırıyorsun. URL'nin neye benzediğini kimin umursadığını söylediğinde, iyi REST umursar, çok. Ve REST neden OOP ile uyumlu olsun ki?
shmish111

Hayır, biraz daha
görmedim

4

Örneğin, Curl, Apache ve PHP ile çalışır.

PHP dosyası:

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

Konsol komutu:

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

Çıktı:

GET
{"the": "body"}

Eğlenceli deneme! PHP yalnızca $_POSTgövde bir POST isteği gönderildiğinde ve application/x-www-form-urlencoded. Bu, vücudun bir GETtalepte göz ardı edildiği anlamına gelir . Bu durumda: $_GETve $_POSTbu noktada zaten çok yanıltıcı. Çok daha iyi kullanımphp://input
Martin Muzatko

3

IMHO sadece JSONkodlanmış (yani. encodeURIComponent) Gönderebilir URL, bu şekilde HTTPözellikleri ihlal JSONve sunucu almak.


28
Evet ama asıl mesele uzunluk limiti tho, bununla nasıl başa çıkabiliriz?
Sebas

2

GET ile bir istek gövdesi kullanmaktan çok daha iyi seçeneklerin bir listesine sahipsiniz.

Her bir kategori için kategorileriniz ve öğeleriniz olduğunu varsayalım. Her ikisi de bir id ile tanımlanmalıdır (bu örnek için "catid" / "itemid"). Belirli bir "sırayla" başka bir "sortby" parametresine göre sıralamak istiyorsunuz. "Sortby" ve "order" için parametreleri iletmek istiyorsunuz:

Yapabilirsin:

  1. Sorgu dizeleri kullanın, ör. example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Yollar için mod_rewrite (veya benzeri) kullanın: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. İstekle ilettiğiniz tek tek HTTP başlıklarını kullanma
  4. Bir kaynağı almak için farklı bir yöntem kullanın, örneğin POST.

Hepsinin dezavantajları vardır, ancak bir vücut ile bir GET kullanmaktan çok daha iyidir.


0

Popüler bir araç bunu kullansa bile, bu sayfada sıkça belirtildiği gibi, spesifikasyon tarafından yasaklanmamış olmasına rağmen, çok egzotik olmak hala oldukça kötü bir fikir olduğunu düşünüyorum.

Birçok ara altyapı bu tür talepleri reddedebilir.

Örneğin olarak, bu gibi web sitesinde önünde bulunan CDN bazılarını kullanarak unutun one :

Bir görüntüleyici GETisteği bir gövde içeriyorsa, CloudFront görüntüleyiciye bir HTTP durum kodu 403 (Yasak) döndürür.

Ve evet, istemci kitaplıklarınız da bu yorumda bildirildiği gibi bu tür isteklerin gönderilmesini desteklemeyebilir .


0

Spring framework's RestTemplate'i istemci programımda kullanıyorum ve sunucu tarafında bir Json gövdesi ile bir GET isteği tanımladım. Birincil amacım sizinkilerle aynı: istek çok sayıda parametreye sahip olduğunda, bunları vücuda koymak, onları uzun süreli URI dizesine koymaktan daha düzenli görünüyor. Evet?

Ancak, ne yazık ki, çalışmıyor! Sunucu tarafı aşağıdaki istisnayı attı:

org.springframework.http.converter.HttpMessageNotReadableException: Gerekli istek gövdesi eksik ...

Ancak ileti gövdesinin istemci kodum tarafından doğru bir şekilde sağlandığından eminim, bu yüzden sorun nedir?

RestTemplate.exchange () yöntemini izledim ve aşağıdakileri buldum:

// 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();
        }
        ...
    }
}

Lütfen executeInternal () yönteminde, 'bufferedOutput' giriş bağımsız değişkeninin kodum tarafından sağlanan ileti gövdesini içerdiğine dikkat edin. Hata ayıklayıcıdan gördüm.

Ancak, preparConnection () nedeniyle, executeInternal () öğesindeki getDoOutput () yöntemi her zaman false değerini döndürür, bu da bufferedOutput öğesini tamamen yok sayılır! Çıkış akışına kopyalanmaz.

Sonuç olarak, sunucu programım ileti gövdesi almadı ve bu özel durumu attı.

Bu, Bahar çerçevesinin RestTemplate'i hakkında bir örnektir. Mesele şu ki, ileti gövdesi artık HTTP spec tarafından yasaklanmış olmasa bile, bazı istemci veya sunucu kitaplıkları veya çerçeveleri hala eski spesifikasyona uyup mesaj gövdesini GET isteğinden reddedebilir.


Spesifikasyonu veya yorumları burada doğru şekilde okumuyorsunuz. İstek gövdesini bırakarak Müşteriler ve sunucuların olduğu spec içinde. GET istek gövdelerini kullanmayın.
Evert

@Evert yorumları doğru okumadım ya da okumadın mı? :) Paul Morgan'ın cevabına (en çok isabet eden cevap) yukarı kaydırırsanız ve yorumları dikkatlice okursanız, bunu bulacaksınız: "" HTTP / 1.1 spec "olarak adlandırılan RFC2616 artık kullanılmıyor. 2014'te yerini aldı RFC 7230-7237. Alıntı "ileti işlenirken ileti gövdesi göz ardı EDİLMELİDİR" silindi. Şimdi sadece "İstek ileti çerçeveleme, yöntem bir ileti gövdesi için herhangi bir kullanım tanımlamasa bile yöntem anlambiliminden bağımsızdır ... "
Zhou

@Evert Ayrıca, Bahar önyükleme arka ucumu test etmek için "emin" REST test programı kullanıyordum. Hem emin hem de Spring-boot sunucu tarafı JET gövdesini GET isteği için sakladı! Yalnızca Sping çerçevesinin RestTemplate'i, gövdeyi GET isteklerinden düşürür, bu nedenle Spring-boot, dinlenme ve RestTemplate, hangisi yanlış / yanlış?
Zhou

@Evert Last ama lease değil, insanları GET isteklerinde beden kullanmaya teşvik etmedim, aksine, Sping-framework'ün RestTemplate'inin kaynak kodunu analiz ederek bunu YAPMAYIN, bu yüzden neden benim Cevap?
Zhou

Cevabını küçümsemedim. Sadece herhangi bir HTTP uygulama bırakarak GET isteği etmediğini açıkça ediyorum olduğu spec.
Evert
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.