Soru REST'te PUT vs POST


HTTP / 1.1 Spec'a göre:

POST yöntem, kaynak sunucu tarafından belirtilen kaynağın yeni bir bağımlı olarak istekte bulunan varlığı kabul etmesini istemek için kullanılır. Request-URI içinde Request-Line

Diğer bir deyişle, POST için kullanılır yaratmak.

PUT yöntem, ilişikteki varlığın tedarik edilen ürünün altında saklanmasını ister. Request-URI. Eğer Request-URI varolan bir kaynağa başvuruda bulunur, ilişikteki varlık, kökenden gelen sunucuda bulunan değiştirilmiş bir sürüm olarak düşünülmelidir. Eğer Request-URI varolan bir kaynağa işaret etmez ve URI istekte bulunan kullanıcı aracısı tarafından yeni bir kaynak olarak tanımlanabilir, kökeni sunucusu bu URI ile kaynağı oluşturabilir. "

Yani, PUT için kullanılır oluştur veya güncelle.

Yani, bir kaynak yaratmak için hangisi kullanılmalı? Ya da her ikisini de desteklemeli?


4468
2018-03-10 14:25


Menşei


HTTPbis'teki tanımların kullanılması yararlı olabilir - Roy bunları açıklığa kavuşturmak için adil bir iş koydu. Görmek: tools.ietf.org/html/... - Mark Nottingham
@ MarkNottingham'ın son revizyona getirdiği yorumları getirmek için POST ve KOYMAKHTTPbis'te tanımlandığı gibi. - Marius Butuc
Bana öyle geliyor ki, bu tartışma, RAT operasyonları açısından HTTP Metotlarını tanımlayarak, REST'i basitleştiren ortak uygulamadan ortaya çıkmıştır. - Stuporman
Talihsizce ilk cevaplar POST hakkında yanlış. Farklılıkların daha iyi bir açıklaması için cevabımı kontrol edin: stackoverflow.com/a/18243587/2458234 - 7hi4g0
PUT ve POST hem güvenli olmayan yöntemlerdir. Ancak POST, PUT idempotent değil. - Daha fazlasını görün: restcookbook.com/HTTP%20Methods/put-vs-post/... - Dinesh Saini


Cevaplar:


Genel: 

Oluşturmak için hem PUT hem de POST kullanılabilir.

"Eylemi ne yapıyorsun?" Diye sormalısın. neyi kullanmanız gerektiğini ayırt etmek. Soru sormak için bir API tasarladığınızı varsayalım. POST kullanmak istiyorsanız, bunu bir soru listesine yaparsınız. PUT kullanmak istiyorsanız, bunu belirli bir soruya yaparsınız.

Büyük her ikisi de kullanılabilir, bu yüzden RESTful tasarımımda hangisini kullanmalıyım?

Hem PUT hem de POST'u desteklemeniz gerekmez.

Kullanılan olan size kalmış. Ancak, istekte hangi nesneyi referans olarak kullandığınıza bağlı olarak doğru olanı kullanmayı unutmayın.

Bazı hususlar:

  • Açıkça oluşturduğunuz URL nesnelerini adlandırır veya sunucunun karar vermesine izin verir misiniz? Bunları isimlendirirseniz, PUT kullanın. Sunucunun karar vermesine izin verirseniz POST'u kullanın.
  • PUT idempotent, bu yüzden bir nesneyi iki kez PUT yaparsanız, hiçbir etkisi olmaz. Bu güzel bir özellik, bu yüzden mümkün olduğunda PUT kullanırdım.
  • Aynı nesne URL'sine sahip PUT ile bir kaynağı güncelleyebilir veya oluşturabilirsiniz.
  • POST ile bir URL'de değişiklik yapmak için aynı anda gelen 2 istek olabilir ve bunlar nesnenin farklı bölümlerini güncelleyebilir.

Bir örnek:

Bu konuda SO ile ilgili başka bir cevabın bir parçası olarak aşağıdakileri yazdım:

POST:

Bir kaynağı değiştirmek ve güncellemek için kullanılır

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Aşağıdaki bir hata olduğunu unutmayın:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

URL henüz oluşturulmamışsa   oluşturmak için POST kullanmamalı   adı belirlerken. Bu olmalı   'kaynak bulunamadı' hatasıyla sonuçlanır   Çünkü <new_question> bulunmuyor   Henüz. PUT <new_question>   önce sunucudaki kaynak.

Yapabilirsin ama   POST kullanarak bir kaynak oluşturmak için:

POST /questions HTTP/1.1
Host: www.example.com/

Bu durumda kaynak olduğunu unutmayın.   ad belirtilmemiş, yeni nesneler   URL yolu size iade edildi.

KOYMAK: 

Kaynak oluşturmak için kullanılır veya   üzerine yaz. Siz belirlerken   yeni URL kaynakları.

Yeni bir kaynak için:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

Mevcut bir kaynağın üzerine yazmak için:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

3487
2018-03-10 14:29



Bence PUT iddialı olduğu gerçeğini yeterince vurgulayamaz: Eğer ağın şişirilmiş olması ve istemcinin isteğinin yerine getirilip getirilmediğinden emin olmaması durumunda, sadece ikinci (veya 100) bir zaman gönderebilir ve HTTP spec, bunun bir kez gönderme ile aynı etkiye sahip olduğunu belirtiyor. - Jörg W Mittag
@ Jörg W Mittag: Gerekli değil. İkinci kez 409 Çatışması veya istek değiştirilmiş ise bir şey (başka bir kullanıcı tarafından veya ilk istek kendisi ile geçti) geri verebilir. - Mitar
Yanılmıyorsam, stresli olmamız gereken PUT’in tanımlanmış idempotent olmak. Sunucunuzu doğru şekilde davranacak şekilde yazmanız gerekiyor, evet? Belki de "PUT, taşımanın, örneğin, önbelleğe alma gibi davranışı etkileyebilecek idrara çıkma duygusu almasına neden olur." - Ian Ni-Lewis
@ JörgWMittag Idempotence catchphrase? "Arkadaşımı yolla ve gönder ve gönder" e ne dersin, sonunda bir fark yaratmıyor. - James Beninger
Onları şöyle düşünür: PUT = ekleme veya güncelleme; POST = ekle. Yani iki PUT yaptığınızda - iki yeni kayıt yaptığınızda yeni bir kayıt alırsınız - iki yeni kayıt alırsınız. - Eugen Konkov


Web'de iddiaları bulabilirsiniz

Ne de doğru.


PUT ve POST arasında seçim yapmak daha iyidir. idempotence eylemin

KOYMAK Bir kaynak oluşturmayı ima eder - verilen URL'de mevcut olan her şeyi başka bir şeyle tamamen değiştirir. Tanım olarak, bir PUT idempotent. İstediğiniz kadar yapın ve sonuç aynı. x=5 idempotent. Önceden var olup olmadığına bir kaynak koyabilirsiniz (örneğin, Yarat veya Güncelle)!

POST Bir kaynağı günceller, bir yardımcı kaynak ekler veya bir değişikliğe neden olur. Bir POST, bu şekilde iddialı değildir. x++ idempotent değildir.


Bu argüman ile PUT, oluşturacağınız şeyin URL'sini bildiğiniz zaman yaratmak içindir. POST, oluşturmak istediğiniz şeylerin kategorisi için "fabrika" veya yöneticinin URL'sini biliyorsanız oluşturulmasında kullanılabilir.

yani:

POST /expense-report

veya:

PUT  /expense-report/10929

1882
2018-04-22 14:55



Aynı fikirdeyim, her ne pahasına olursa olsun, herhangi bir endişe uyandırmalı, çünkü bu yanlışlığı yapmak birçok beklenmedik hataya sebep olabilir. - Josh
POST bir kaynağı güncelleyebilirse, bu nasıl bir fikir değil? Eğer PUT kullanarak bir öğrenciyi değiştirirsem ve bunu 10 kat yaparsam, bir kere yaparsam öğrencilerin yaşı aynıdır. - Schneider
@Schneider, bu durumda sunucunuz idempotence garanti etmek için ekstra çaba harcıyor, ama bu reklam değil. Tarayıcılar, böyle bir POST isteğini yeniden yüklemeye çalışırlarsa kullanıcıyı uyarır. - Tobu
@Schneider POST bir yan kaynak oluşturabilir; dolayısıyla koleksiyona POST yapabilirsiniz POST / gider raporları ve tamamen benzer olsalar bile, gönderdiğiniz isteklerin miktarı olarak sunucunuzda çok sayıda varlık (masraf raporları) oluşturacaktır. Otomatik olarak artırılmış birincil anahtarla DB tablosunda (/ masraf raporlarında) aynı satırı eklerken bunu düşünün. Veri aynı kalır, anahtar (bu durumda URI) sunucu tarafından oluşturulur ve her diğer insert (istek) için farklıdır. Yani, POST etkisi kutu idempotent olmak, ama aynı zamanda Mayıs ayı değil. Bu nedenle, POST değil İdempotent. - Snifff
İki özelliğe sahip olabilecek varlıklarımız olduğunu varsayalım - name ve date. Var olan bir varlığımız varsa name ve dateancak daha sonra yalnızca bir name, doğru davranış KOYMAK yok etmek olurdu date varlığın POST Yalnızca belirtilen özellikleri güncelleyemez ve belirtilmemiş özellikleri istekte bulunulmadan önceki gibi bırakabilir. Doğru / mantıklı geliyor mu, yoksa yanlış bir kullanım mı? KOYMAK (Referansları gördüm YAMAki daha uygun görünüyor, ama henüz mevcut değil)? - Jon z


  • POST bir URL'ye bir çocuk kaynağı oluşturur a sunucu tanımlı URL.
  • KOYMAK bir URL'ye kaynağı oluşturur / değiştirir bütünüyle müşteri tanımlı URL.
  • YAMA bir URL'ye güncellemeler Bölüm kaynağın bu müşteri tanımlı URL’de.

PUT ve POST için ilgili şartname RFC 2616 §9.5ff.

POST bir çocuk kaynağı oluşturur, bu yüzden POST /items altında yaşayan bir kaynak oluşturur /items kaynak. Örneğin. /items/1. Aynı gönderi paketini iki kez göndermek iki kaynak oluşturur.

KOYMAK bir kaynağı oluşturmak veya değiştirmek için Müşteri tarafından bilinen URL.

Bu nedenle: KOYMAK CREATE için yalnızca bir kaynak yaratılmadan önce istemcinin url'yi bildiği bir adaydır. Örneğin. /blogs/nigel/entry/when_to_use_post_vs_put başlık kaynak anahtar olarak kullanıldığında

KOYMAK Varsa, bilinen URL'deki kaynağı değiştirir, böylece aynı isteği iki kez göndermek hiçbir etkiye sahip değildir. Diğer bir deyişle, PUT çağrıları idempotent.

RFC şöyle okur:

POST ve PUT istekleri arasındaki temel fark, İstek-URI'nin farklı anlamında yansıtılır. POST isteğinde bulunan URI, ilişikteki öğeyi ele alacak kaynağı tanımlar. Bu kaynak, bir veri kabul etme işlemi, başka bir protokolün ağ geçidi veya ek açıklamaları kabul eden ayrı bir varlık olabilir. Tersine, bir PUT isteğindeki URI, talebi içeren tüzel kişiyi tanımlar - kullanıcı aracısı, URI'nin ne amaçladığını bilmektedir ve sunucu, isteği başka bir kaynağa uygulamayı denememelidir. Sunucu, isteğin farklı bir URI'ye uygulanmasını istiyorsa,

Not: PUT daha çok kaynakları güncellemek için kullanılmıştır (bunları bütünüyle değiştirerek), fakat son zamanlarda mevcut kaynakların güncellenmesi için PATCH kullanımıyla ilgili bir hareket vardır, çünkü PUT tüm kaynağın yerini aldığını belirtir. RFC 5789.


563
2018-04-07 05:52



Ya da çitin diğer tarafından: PUT, istemci, sonuçta ortaya çıkan kaynağın adresini belirlerse, POST sunucuyu yaparsa POST. - DanMan
Bu cevabın, @DanMan'ın çok basit bir şekilde işaret ettiği şeyi daha net hale getirmek için düzenlenmesi gerektiğini düşünüyorum. Burada en değerli bulduklarım, sonunda sadece tüm kaynağı değiştirmek için bir PUT kullanılması gerektiğini belirten not. - Hermes
PATCH, en az birkaç yıl boyunca gerçekçi bir seçenek değil, ancak ideolojiye katılıyorum. - crush
Anlamaya çalışıyorum ama bir şey yaratmak için PUT kullanmak, eğer müşteri kaynağın henüz var olmadığından emin olduğunu bilerek mantıklı olur, değil mi? Blog örneğini takip ederek, birkaç yıl içinde yüzlerce blog yazısı oluşturduğunuzu ve iki yıl önce bir yayın için yaptığınız kazayla aynı başlığı aldığınızı varsayalım. Şimdi gittin ve niyetlenmeyen bu yazıyı değiştirdin. Bu nedenle, oluşturmak için PUT kullanmak istemcinin neyin alındığını ve neyin yapılmadığını takip etmesini gerektirecek ve kazalara ve istenmeyen yan etkilere yol açabileceği gibi, birbirinden tamamen farklı iki şey yapan yollara sahip olabilir? - galaxyAbstractor
Haklısın. Bir blog yayınını varolan bir URL ile aynı anda yayınlamak varolan bir gönderiye bir güncelleme getirecektir (bir GET ile ilk defa kontrol edebileceğiniz halde). Bu, yalnızca başlığı URL olarak kullanmanın neden kötü bir fikir olacağını belirtir. Ancak, verilerde doğal bir anahtarın var olduğu her yerde çalışırdı ... ki bu benim tecrübemde nadirdir. Veya GUID kullandıysanız - Nigel Thorne


Özet:

Yaratmak:

Aşağıdaki şekilde hem PUT hem de POST ile gerçekleştirilebilir:

KOYMAK

oluşturur  ile yeni kaynak newResourceId / Kaynak URI'sı altında tanımlayıcı olarak veya Toplamak.

PUT /resources/<newResourceId> HTTP/1.1 

POST

oluşturur bir / kaynak URI'sı altında yeni kaynak veya Toplamak. Genellikle tanımlayıcı sunucu tarafından iade edilir.

POST /resources HTTP/1.1

Güncelleştirme:

kutu bir tek aşağıdaki şekilde PUT ile gerçekleştirilir:

KOYMAK

Kaynağı güncelle existingResourceId / Kaynak URI'sı altında tanımlayıcı olarak veya Toplamak.

PUT /resources/<existingResourceId> HTTP/1.1

Açıklama:

Genel olarak REST ve URI ile çalışırken, sahip olduğunuz genel üzerinde ayrıldı ve özel üzerinde sağ. jenerik genellikle denir koleksiyonları ve daha fazlası özel öğeler çağrılabilir kaynak. Unutmayın ki kaynak içerebilir Toplamak.

Örnekler:

<- jenerik - spesifik ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

POST kullandığınızda her zaman bir Toplamak, ne zaman diyorsun ki:

POST /users HTTP/1.1

yeni bir kullanıcı gönderiyorsunuz kullanıcılar  Toplamak.

Eğer devam ederseniz ve böyle bir şey denerseniz:

POST /users/john HTTP/1.1

işe yarayacak, ama semantik olarak bir kaynak eklemek istediğinizi söylüyorsunuz John  Toplamak altında kullanıcılar  Toplamak.

Bir kez PUT kullanıyorsunuz kaynak ya da tek bir parça, muhtemelen içinde Toplamak. Yani dediğin zaman:

PUT /users/john HTTP/1.1

Sunucu güncellemesine söylüyorsunuz ya da mevcut değilse oluşturun. John  kaynak altında kullanıcılar  Toplamak.

spec:

Speklerin bazı önemli kısımlarını vurgulayayım:

POST

POST yöntem, kaynak sunucu isteğinde kullanılır kabul etmek İstekte bulunan varlık yeni ast İstek satırındaki İstek-URI ile tanımlanan kaynağın

Böylece yeni bir kaynak üzerinde Toplamak.

KOYMAK

KOYMAK yöntem, ilişikteki varlığın olmasını ister saklanmış sağlanan İstek-URI altında. İstek-URI bir zaten mevcut kaynak, ilişikteki varlık bir değiştirilmiş versiyon kökeni sunucuda bulunanın. İstek-URI'sı varsa var olanı işaret etmemek kaynak ve bu URI yetenekli olarak tanımlanmak yeni kaynak istekte bulunan kullanıcı aracısı ile, kaynak sunucu yaratmak Bu URI ile kaynak. "

Bu nedenle, varoluşu temelinde kaynak.

Referans:


164
2017-08-14 22:47



Bu gönderi, POST'un, belirli bir URI konumundaki "bir şey" i açıkça tanımlarken, POST'un belirli bir koleksiyona (URI) "bir şey" eklediğini anlamamda bana yardımcı oldu. - kwah
Bu en iyi cevabı burada, düşünüyorum: Bu "POST bir kaynağı güncelleyemez" saçmalık. İfadenizi beğendim, "Güncelleme sadece PUT ile yapılabilir". - Thomas
Hayır, PUT güncelleme veya oluşturma için değil. Değiştirmek için. Oluşturmanın etkisi için hiçbir şeyi bir şeyle değiştiremeyeceğinizi unutmayın. - thecoshman
@ 7hi4g0 PUT, tam bir yenileme ile güncellemek içindir, başka bir deyişle, yerini alır. Hiçbir şeyi bir şeyle değiştirmezsin ya da tamamen yeni bir şeyle. PUT, küçük bir değişiklik yapmak için değildir (müşterinin bu küçük değişikliği yapıp yapmadığınız sürece ve tüm yeni sürüme sahip olmadıkça, aynı kalan durumda bile). Kısmi modifikasyon için, PATCH seçim yöntemidir. - thecoshman
@thecoshman Yapabilirdiniz, ama yaratmanın da orada kaplandığı çok açık olmaz. Bu durumda, açık olmak daha iyidir. - 7hi4g0


"Pragmatik" tavsiyemi eklemek istiyorum. Kaydetmekte olduğunuz nesnenin alınabileceği "id" yi biliyorsanız PUT kullanın. Gelecekte aramalar veya güncellemeler yapabilmeniz için, geri döndürülecek bir veritabanına ihtiyacınız varsa, PUT kullanımı çok işe yaramaz.

Yani: Mevcut bir kullanıcıyı veya istemcinin kimliği oluşturduğu bir kişiyi kaydetmek ve kimliğin benzersiz olduğunu doğrulamak için:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

Aksi halde, nesneyi başlangıçta oluşturmak için POST'u ve nesneyi güncelleştirmek için PUT kullanın:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com

155
2018-01-15 19:59



Aslında olmalı POST /users. (Bunu not et /users çoğul.) Bu, yeni bir kullanıcı yaratma ve onu bir çocuk kaynağı yapma etkisine sahiptir. /users Toplamak. - DavidRR
@DavidRR'nin adil olması, grupların nasıl ele alınacağı diğer bir tartışmadır. GET /users mantıklı, istediğin gibi okur, ama ben iyi olurum GET /user/<id> veya POST /user (söz konusu yeni kullanıcı için yük ile) çünkü doğru bir şekilde okuduğundan 'beni kullanıcılara 5 getir' tuhaf, ama 'bana kullanıcı 5'i al' daha doğal. Muhtemelen yine de çoğullaşma tarafına düşecektim :) - thecoshman


POST, "Bir kullanıcı oluşturmak için girdi, benim için oluştur" ifadesiyle "yeni oluştur" anlamına gelir.

PUT, "Burada kullanıcı 5 için veriler var" bölümünde olduğu gibi, "ekle, var ise değiştir" anlamına gelir.

Kullanıcının URL'sini henüz bilmediğinizden, example.com/users için POST yaparsınız, sunucunun bunu oluşturmasını istersiniz.

Değiştirmek / oluşturmak istediğiniz için example.com/users/id adresine gidin özel kullanıcı.

Aynı verilerle iki kez işaretlemek, farklı kimlikleri olan iki benzer kullanıcı oluşturmak anlamına gelir. Aynı verilerle iki kez durma, kullanıcıyı ilk olarak oluşturur ve onu ikinci kez aynı duruma getirir (değişiklik olmaz). Bir PUT'den sonra aynı durumla sonuçlandığınız zaman, onu kaç kez gerçekleştirirseniz yapın, her seferinde “eşit derecede güçlü” olduğu söylenir - idempotent. Bu, istekleri otomatik olarak yeniden denemek için kullanışlıdır. Artık tarayıcınızdaki geri düğmesine bastığınızda 'tekrar göndermek istediğinizden emin misiniz?'

Genel bir öneri, sunucunuzun kaynaklarınızın URL oluşturulmasının kontrolünde olması gerektiğinde POST'u kullanmaktır. Aksi halde PUT kullanın. POST üzerinden PUT tercih ederim.


144
2017-10-23 14:27



Dağınıklık, genellikle ihtiyacınız olan sadece iki fiil olduğu öğretilmelidir: GET ve POST. Almak için GET, değiştirmek için POST. PUT ve DELETE bile POST kullanılarak gerçekleştirildi. PUT'nin gerçekten ne anlama geldiğini sormak 25 yıl sonra belki de ilk başta yanlış olduğunu bir işaret olarak gördük. REST popülaritesi insanları geçmişteki kötü hatalardan kurtulmamız gereken temel noktalara geri götürdü. POST abartıldı ve şimdi yaygın olarak yanlış öğretildi. En iyi bölüm: "Aynı verilerle iki kez POST yapmak, iki özdeş [kaynak] oluşturmak" anlamına gelir. Harika nokta! - maxpolk
Örneğinizde olduğu gibi kimlik tarafından bir kayıt oluşturmak için PUT'u nasıl kullanabilirsiniz? user 5 eğer henüz mevcut değilse? Demek istemiyorsun update, replace if already exists? ya da başka birşey - Luke
@ Coulton: Yazdıklarımı kastettim. / Kullanıcılar / 5 ve # 5 için PUT henüz kullanmıyorsanız, kullanıcı 5'i eklersiniz. - Alexander Torstling
@Coulton: Ve PUT ayrıca kullanılabilir değiştirmek bir değeri mevcut bütünüyle kaynak. - DavidRR
"POST üzerinden POUT'u tercih et" ... bunu haklı göstermek ister misin? - thecoshman


Oluşturmak için POST ve güncellemek için PUT kullanın. O zaman Ruby on Rails böyle yapıyor.

PUT    /items/1      #=> update
POST   /items        #=> create

104
2018-03-10 14:28



POST /items önceden tanımlanmış bir kaynağa ('öğe') yeni bir öğe ekler. Cevap, "bir grup oluştur" demez. Bunun neden 12 oyu olduğunu anlamıyorum. - David J.
Kutunun dışında Rails, REST aracılığıyla 'grup oluşturma' desteklemiyor. 'Kaynak oluştur' demek istediğim 'bir grup yaratmak' için bunu kaynak koduyla yapmanız gerekir. - David J.
Bu adil bir kılavuz, ancak aşırı basitleştirme. Diğer cevaplardan da anlaşıldığı gibi, her iki yöntem de hem yaratma hem de güncelleme için kullanılabilir. - Brad Koch
Cevabı küçük bir değişiklikle kabul ediyorum. Kaynağı tamamen güncelleştirmek için POST ve PUT komutunu kullanın. Kısmi güncellemeler için PUT veya PATCH kullanabiliriz. Bir grubun durumunu güncellemek istediğimizi söyleyelim. PUT / groups / 1 / status statüsünü talep yükü ya da YARDIM / Grup / 1 'i, yükteki eylemle ilgili detaylarla kullanabiliriz - java_geek
Ayrıca açıkça belirtilmelidir PUT /items/42 için de geçerlidir oluşturma kaynak, ancak müşteri, kaynağa ad verme ayrıcalığına sahipse. (Rails müşteriye bu ad ayrıcalıklarına izin veriyor mu?) - DavidRR


REST bir çok üst düzey kavram. Aslında, hiç HTTP'den bile bahsetmiyor!

REST'i HTTP'de nasıl uygulayacağınız konusunda herhangi bir şüpheniz varsa, her zaman Atom Yayın Protokolü (AtomPub) Şartname. AtomPub, HTTP ve REST armatürleri tarafından geliştirilen HTTP ile RESTful web servislerini yazmak için bir standarttır, REST'in mucidi Roy Fielding ve HTTP'nin kendisinin (mucit) mucidi.

Aslında, AtomPub'u doğrudan kullanabileceksiniz bile. Bloglama topluluğundan çıkarken, bloglama ile hiçbir şekilde sınırlandırılmamıştır: HTTP yoluyla keyfi kaynakların keyfi (iç içe) koleksiyonları ile RESTLA etkileşimde bulunmak için kullanılan genel bir protokoldür. Uygulamanızı iç içe geçmiş bir kaynak koleksiyonu olarak temsil ederseniz, AtomPub'u kullanabilirsiniz ve PUT veya POST kullanıp kullanmayacağınıza, hangi HTTP Durum Kodlarının dönüleceğine ve tüm bu ayrıntılara endişelenmeyebilirsiniz.

Bu, AtomPub'un kaynak oluşturma konusunda söylemesi gereken şeydir (bölüm 9.2):

Bir Koleksiyona üye eklemek için istemciler Koleksiyonun URI'sine POST istekleri gönderir.


57
2018-03-10 15:27



PUT'nin kaynak oluşturmasına izin vermede yanlış bir şey yoktur. Sadece müşterinin URL'yi sağladığı anlamına geldiğini unutmayın. - Julian Reschke
PUT'nin kaynak yaratmasına izin vermede çok yanlış bir şey var: istemci URL'yi sağlıyor. Bu sunucunun işi! - Joshcodes
@Joshcodes Her zaman istemci kimlikleri oluşturmak için sunucunun görevi olduğu durumda değildir. Müşterilerin kaynak kimliği olarak bir çeşit UUID oluşturmasına olanak veren tasarımları giderek daha fazla gördüm. Bu tasarım, özellikle ölçeği artırmak için kendini ödünç verir. - Justin Ohms
@JustinOhms İstemci tarafından oluşturulan kimlikler hakkındaki noktanıza katılıyorum (yan not: 2008'den beri benim tarafımdan tasarlanan tüm sistemler istemcinin UUID / Guid olarak kimliğini oluşturmasını gerektirir). Bu, müşterinin URL'yi belirtmesi gerektiği anlamına gelmez. - Joshcodes
@Joshcodes Endişeleri ayırmak meselesi. URL’nin üretildiği yer aslında küçük bir sonuçtur. Evet, sunucu içeriği doğru URL'den göndermekle sorumludur, ancak bu, bir sunucunun yanlış bir URL'deki bir isteğe yanıt vermesini sınırlandırmaz. Bu durumda sunucunun doğru yanıtı 308'dir. Uygun bir istemci daha sonra doğru URL'de PUT'yi yeniden dener. Başka bir örnek, tüm düğümlerin istemciler tarafından sağlanan tüm kaynakları bilmediği dağıtılmış bir sistemdir. Burada oluşturulacak bir PUT tam olarak geçerli olacaktır, çünkü bu sunucu düğümü için kaynak mevcut değildir. - Justin Ohms


HTTP + REST API'sine sahip bir sunucuda kaynak oluşturmak için PUT veya POST kullanıp kullanmama kararı, URL yapısının sahibi olan kullanıcıya dayanır. Müşteriyi tanımak veya tanımlamaya katılmak, URL yapısını SOA'dan kaynaklanan istenmeyen bağlantılara benzer gereksiz bir bağlantıdır. Kaçış türlerinden biri, REST'in bu kadar popüler olmasının sebebidir. Bu nedenle, Kullanılacak uygun yöntem POST. Bu kuralın istisnaları vardır ve müşteri, kullandığı kaynakların konum yapısı üzerinde kontrolü ellerinde tutmak istediğinde ortaya çıkar. Bu nadirdir ve muhtemelen başka bir şeyin yanlış olduğu anlamına gelir.

Bu noktada bazı insanlar, eğer Sığınakta-URL kullanılır, istemci kaynağın URL'sini bilir ve bu nedenle PUT kabul edilebilir. Sonuçta, bu yüzden noronik, normalleştirilmiş, Ruby on Rails, Django URL'leri önemlidir, Twitter API'sine bakın ... bla bla blah. Bu insanların anlaması gerekiyor Restful-URL diye bir şey yoktur ve şu Roy Fielding'in kendisi bunu belirtiyor:

Bir REST API'sı, sabit kaynak adlarını veya hiyerarşilerini tanımlamamalıdır (bir   İstemcinin ve sunucunun açık bir şekilde birleştirilmesi). Sunucular özgürlüğe sahip olmalı   kendi isimlerini kontrol etmek için. Bunun yerine, sunucuların talimat vermesine izin verin   HTML'de yapıldığı gibi uygun URI'leri nasıl oluşturacağına dair istemciler   medya içindeki bu talimatları tanımlayarak formlar ve URI şablonları   türleri ve bağlantı ilişkileri. [Buradaki başarısızlık, müşterilerin olduğunu ima eder.   bant dışı bilgiler nedeniyle bir kaynak yapısını varsayarak   veriye yönelik eşdeğer olan alana özgü bir standart   RPC'nin fonksiyonel bağlanması].

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

Bir fikir Sığınakta-URL sunucu URL yapısından sorumlu olduğu için REST'in bir ihlalidir ve bağlantıdan kaçınmak için nasıl kullanılacağına karar vermekte özgür olmalıdır. Bu kafa karıştırırsa, API tasarımında kendini keşfetmenin önemini okursunuz.

Kaynak oluşturmak için POST kullanma, bir tasarım düşüncesiyle birlikte gelir çünkü POST, idempotent değildir. Bu, bir POST'u birkaç kez tekrarlamanın, her defasında aynı davranışı garanti etmediği anlamına gelir. Bu, insanları, yapmamaları gerektiğinde kaynak oluşturmak için PUT kullanarak korkutur. Yanlış olduğunu biliyorlar (POST CREATE için) ama yine de bunu yapıyorlar çünkü bu sorunu nasıl çözeceklerini bilmiyorlar. Bu endişe aşağıdaki durumda gösterilmiştir:

  1. İstemci sunucuya yeni bir kaynak POST.
  2. Sunucu isteği işler ve bir yanıt gönderir.
  3. Müşteri hiç bir zaman cevabı almaz.
  4. Sunucu, istemcinin yanıtı almadığından habersizdir.
  5. İstemcinin kaynak için bir URL'si yoktur (bu nedenle PUT bir seçenek değildir) ve POST'u tekrarlar.
  6. POST idempotent ve sunucu değil…

Adım 6, insanların genellikle ne yapmaları gerektiği konusunda kafalarının karıştığı yer. Bununla birlikte, bu sorunu çözmek için bir kloz oluşturmak için bir sebep yoktur. Bunun yerine, HTTP belirtilen şekilde kullanılabilir RFC 2616 ve sunucu yanıtları:

10.4.10 409 Çatışma

İstek, mevcut bir ihtilaf nedeniyle tamamlanamadı   kaynağın durumu. Bu koda yalnızca izin verilen durumlarda izin verilir   kullanıcının çatışmayı çözmesi beklenebilir ve   isteği yeniden gönderin. Tepki vücut yeterli içermelidir

Kullanıcıya, çatışmanın kaynağını tanıması için bilgi.   İdeal olarak, yanıt kuruluşu,   sorunu çözmek için kullanıcı veya kullanıcı aracısı; Ancak, bu olmayabilir   Mümkün ve gerekli değildir.

Çatışmaların bir PUT isteğine yanıt olarak ortaya çıkması en olasıdır. İçin   Örneğin, sürüm oluşturuluyor ve PUT olan varlık   tarafından yapılanlarla çelişen bir kaynağa yapılan değişiklikler   önceki (üçüncü taraf) isteği, sunucu 409 yanıtını kullanabilir   isteği tamamlayamadığını belirtmek için. Bu durumda   Yanıt varlığı, muhtemelen arasındaki farkların listesini içerecektir   İçerik-Türü yanıtı tarafından tanımlanan bir biçimde iki sürüm.

409 Çatışma durum koduyla yanıt vermek doğru başvurudır çünkü:

  • Sistemdeki halihazırda bir kaynağa uyan bir kimliği olan bir veri POST'unun yapılması, “kaynağın mevcut durumuyla çelişen” dir.
  • Önemli olan, istemci için sunucunun kaynağı olduğunu ve uygun eylemi aldığını anladığından beri. Bu, kullanıcının çatışmayı çözebileceği ve isteği yeniden gönderebileceği beklenen bir durumdur. ”
  • Çakışan kimliği ve kaynağa ilişkin uygun önkoşulları içeren kaynağın URL'sini içeren bir yanıt, RFC 2616 için ideal durum olan “sorunu çözmek için kullanıcı veya kullanıcı aracısı için yeterli bilgi” sağlayacaktır.

RFC 7231’nin 2616’ya Değiştir’e göre güncellenmesi

RFC 7231 2616 yerine ve için tasarlanmıştır Bölüm 4.3.3 POST için olası olası yanıtı açıklar

Bir POST işleminin sonucu, bir   Varolan bir kaynağın temsil edilmesi, bir kaynak sunucu MAYIS yönlendirmesi   303 (Bkz. Diğer) yanıtı göndererek bu kaynağa kullanıcı aracısı   Konum alanında mevcut kaynağın tanımlayıcısı ile. Bu   kullanıcı aracısına bir kaynak tanımlayıcısı sağlama yararları vardır   ve temsilin daha uygun bir yöntemle aktarılması   kullanıcı için ek bir talep olsa da, paylaşımlı önbelleğe alma   Aracı zaten önbelleğe alınmış temsilciliğe sahip değil.

Artık bir POST'un tekrarlanması durumunda 303'ü geri döndürmek cazip gelebilir. Ancak bunun tersi doğrudur. Bir 303 döndürmek, birden çok istek oluşturma (farklı kaynaklar oluşturma) aynı içeriği döndürürse mantıklı olur. Bir örnek, "istek mesajınızı gönderdiğiniz için teşekkür ederiz" ifadesinin, müşterinin her defasında yeniden indirilmemesi gerektiğidir. RFC 7231 hala bölüm 4.2.2'de POST'un idempotent olmayacağını ve POST'un yaratmak için kullanılmasının sürdürülmesini sürdürmektedir.

Bu konuda daha fazla bilgi için şunu okuyun makale.


53
2017-10-29 23:00



409 Çatışma yanıtı, zaten var olan bir kullanıcı adıyla yeni bir hesap oluşturmaya çalışmak gibi uygun bir kod mu? Özellikle sürüm çakışmaları için 409 kullanıyorum, ancak cevabınızı okuduktan sonra, herhangi bir "yinelenen" istek için kullanılmaması gerekip gerekmediğini merak ediyorum. - Eric B.
@EricB. Evet, "kaynağın mevcut durumuyla çelişki nedeniyle" açıkladığınız durumda işlem başarısız oluyor. Ayrıca, kullanıcının çatışmayı çözebileceğini ve mesaj gövdesinin yalnızca kullanıcı adını zaten mevcut olduğu konusunda bilgilendirmesi gerektiğini düşünmek mantıklıdır. - Joshcodes
@Joshcodes çatışma çözme süreci hakkında daha fazla şey söyleyebilir misiniz? Bu durumda, kullanıcı adı zaten mevcutsa, müşterinin son kullanıcıyı farklı bir kullanıcı adı için sorması beklenir mi? İstemci, kullanıcı adını değiştirmek için POST kullanmaya çalışıyorsa ne olur? PST, parametrelerin güncellenmesi için hala kullanılsa da, POST, bir kerede mi yoksa birkaç mu yoksa nesne mi oluşturmak için kullanılır? Teşekkürler. - BFar
@ BFar2 eğer kullanıcı adı zaten mevcutsa, müşteri kullanıcıyı yönlendirmelidir. Kullanıcı adını değiştirmek için, kullanıcı adının değiştirilmiş olan önceden oluşturulmuş bir kaynağın parçası olduğunu varsayarak, PUT, doğru olduğundan, POST, her zaman ve güncellemeler için PUT kullanılır. - Joshcodes
Kısa ve etkili dili kullanarak şeyleri açıklamak da istenen bir beceridir. - Junchen Liu


Bu tavsiyeyi seviyorum RFC 2616'nın PUT tanımı:

POST ve PUT istekleri arasındaki temel fark, İstek-URI'nin farklı anlamında yansıtılır. POST isteğinde bulunan URI, ilişikteki öğeyi ele alacak kaynağı tanımlar. Bu kaynak, bir veri kabul etme işlemi, başka bir protokolün ağ geçidi veya ek açıklamaları kabul eden ayrı bir varlık olabilir. Tersine, bir PUT isteğindeki URI, talebi içeren tüzel kişiyi tanımlar - kullanıcı aracısı, URI'nin ne amaçladığını bilmektedir ve sunucu, isteği başka bir kaynağa uygulamayı denememelidir.

Bu diğer önermeyle burada, PUT en iyi halihazırda bir ada sahip olan kaynaklara uygulanır ve POST varolan bir kaynak altında yeni bir nesne oluşturmak için iyidir (ve sunucu adını verir).

Bunu ve şu anlama gelmek için PUT'deki idempotence gereksinimlerini yorumluyorum:

  • POST, bir koleksiyonun altında yeni nesneler oluşturmak için iyidir (ve idempotent olması gerekmez)
  • PUT, mevcut nesneleri güncellemek için iyidir (ve güncellemenin idempotent olması gerekir)
  • POST, varolan nesnelere (özellikle, bir nesnenin tüm parçasını belirtmeden değiştirerek) güncel olmayan güncelleştirmeler için de kullanılabilir. Bunun hakkında düşünürseniz, koleksiyonun yeni bir üyesini oluşturmak aslında bu tür bir özel durumdur. koleksiyonun bakış açısıyla güncellemek
  • PUT ayrıca, yalnızca istemcinin kaynağa isim vermesine izin verirseniz, oluşturmak için de kullanılabilir. Ancak REST istemcilerinin URL yapısı hakkında varsayımlar yapması gerekmediğinden, bu amaçlanan şeylerin ruhunda daha azdır.

48
2018-01-11 17:18



"POST, mevcut nesneler için (özellikle, bir şeyi tüm nesneyi belirtmeksizin, bir parçanın değişen kısmını değiştiren) güncellemeler için de kullanılabilir." - Snuggs