POST ile istek oluşturun, yanıt kodları 200 veya 201 ve içeriği


125

Bir sisteme yeni bir veri öğesi eklemek olan bir REST servisi yazdığımı varsayalım.

POST yapmayı planlıyorum

http://myhost/serviceX/someResources

Bunun işe yaradığını varsayalım, hangi yanıt kodunu kullanmalıyım? Ve hangi içeriği geri verebilirim?

HTTP yanıt kodlarının tanımlarına bakıyorum ve şu olasılıkları görüyorum:

200: Eylemin sonucunu açıklayan veya içeren bir varlık döndürür ;

201: bu, OLUŞTURULDU anlamına gelir. Anlamı * İstek yerine getirildi ve yeni bir kaynak yaratılmasına neden oldu. Yeni oluşturulan kaynağa, bir Konum başlık alanı tarafından verilen kaynak için en spesifik URI ile yanıtın varlığında döndürülen URI (ler) tarafından referans alınabilir. Yanıt, kullanıcı veya kullanıcı aracısının en uygun olanı seçebileceği kaynak özelliklerinin ve konumların bir listesini içeren bir varlığı içermelidir * ÖNERİSİ. Varlık formatı, Content-Type başlık alanında verilen medya tipiyle belirlenir. *

İkincisi, Http spesifikasyonuna daha uygun geliyor, ancak ne olduğu konusunda hiç net değilim

Yanıt, kaynak özelliklerinin ve konumların bir listesini içeren bir varlığı İÇERMELİDİR.

anlamına geliyor.

Öneriler? Yorumlama?

Yanıtlar:


78

Buradaki fikir, yanıt gövdesinin sizi şeye bağlayan bir sayfa vermesidir:

201 Oluşturuldu

201 (Oluşturuldu) durum kodu, isteğin yerine getirildiğini ve bir veya daha fazla yeni kaynağın oluşturulmasına neden olduğunu gösterir. İstek tarafından oluşturulan birincil kaynak, yanıttaki bir Konum başlığı alanıyla veya herhangi bir Konum alanı alınmadıysa etkin istek URI'si tarafından tanımlanır.

Bu , yeni oluşturulan şeyi bulabileceğiniz URL'yi veren Locationyanıt başlığına bir ekleyeceğiniz anlamına gelir :

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Yanıt gövdesi

Daha sonra yanıt gövdesine neleri dahil etmeniz gerektiğini belirtmeye devam ederler :

201 yanıt yükü tipik olarak, oluşturulan kaynakları tanımlar ve bunlara bağlanır.

Tarayıcıyı kullanan insan için, onlara bakabilecekleri bir şey verirsiniz ve yeni oluşturdukları kaynaklara ulaşmak için tıklayabilirsiniz:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Sayfa yalnızca bir robot tarafından kullanılacaksa, yanıtın bilgisayarda okunabilir olması mantıklıdır:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Veya tercih ederseniz:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

Cevap tamamen size bağlıdır; keyfi olarak istediğiniz şey bu.

Önbellek dostu

Son olarak, oluşturulan kaynağı önceden önbelleğe alabileceğim optimizasyon var (çünkü içeriğe zaten sahibim; yeni yükledim). Sunucu, yeni yüklediğim içerikle saklayabileceğim bir tarih veya ETag döndürebilir:

201 yanıtında ETag ve Last-Modified gibi doğrulayıcı başlık alanlarının anlamı ve amacına ilişkin bir tartışma için Bölüm 7.2'ye bakın .

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Ve ETags tamamen keyfi değerlerdir. Önemli olan tek şey, bir kaynak değiştiğinde (ve önbelleklerin güncellenmesi gerektiğinde) farklı olmalarıdır. ETag genellikle bir karmadır (ör. SHA2). Ancak bir veritabanı rowversionveya artan bir revizyon numarası olabilir. Olacak şey değiştirmek zaman şey değişir.


Şimdiye kadar yanıtınız çok mantıklı görünüyor. Cevabın ontolojisi konusunda biraz endişeliyim, ancak bunun dışında, şartnamenin en olgun yorumu gibi görünüyor. İnsan / makine çıktılarını idare etmenin herhangi bir hafif "duyarlı" yolu olup olmadığını merak ediyorum. ama çoğunlukla "kendi girdinizi önbelleğe alma" öneriniz ilgimi çekiyor. Bildiğim çoğu web uygulaması, kaynağın 1: 1 sürümünü oluşturmayacak. Bir dizenin büyük harf kullanımını normalleştirmek gibi önemsiz bir şey olsa bile. Gönderdiğiniz sürümü, etagın karşı oluşturulduğu sürüm olarak ele almak biraz tehlikeli değil mi?
Anthony

1
@Anthony, önbelleğe alma: 1: 1 dosya depolama uygulaması olabilir. Örneğin WebDAV PUT & POST ile karşılaştırın. İşlenecek çok büyük dosyalar.
kxr

@Anthony Müşteriye bir ETag'ı iade etmek isteyip istemediğiniz size kalmış. İstemcinin az önce yüklediği içerik kaydettiğiniz içerik değilse, ETag'ı iade etmeyin. Esnekliğiniz ve seçiminiz.
Ian Boyd

Yanıtlarınız neden İçerik Uzunluğu eksik?
Vinnie Falco

1
@VinnieFalco Bu, 201 yanıt koduyla ilgili bir yanıttır. İçerik Uzunluğu, açıklama amacıyla çıkarılmıştır.
Ian Boyd

91

Atompub REST API'nin dinlendirici bir hizmetin harika bir örneği olduğunu düşünüyorum . Atompub spesifikasyonundan aşağıdaki parçacığa bakın:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

Sunucu, 201 durum kodu ile başarılı bir oluşturma sinyali verir. Yanıt, Atom Girişinin Üye Giriş URI'sini belirten bir Konum başlığını ve yanıtın gövdesinde bu Girişin bir temsilini içerir.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

Koleksiyon tarafından oluşturulan ve iade edilen Giriş, müşteri tarafından POST edilen Giriş ile eşleşmeyebilir. Bir sunucu Girişteki atom: id, atom: updated ve atom: author değerleri gibi çeşitli öğelerin değerlerini değiştirebilir ve diğer öğeleri ve nitelikleri kaldırmayı veya eklemeyi ya da öğe içeriğini ve nitelik değerlerini değiştirmeyi SEÇİLEBİLİR.


9
Kaynak gigabayt büyüklüğündeyse, oluşturulan kaynağı
iade etmek

10
Kabul! Bu, gerekliliğin optimizasyonu - ama bunu erken yapmak istemezsiniz. Huzurlu ruhlarda tasarım yapmak ve yalnızca gerekli olduğunda istisnalar yapmak önemlidir.
Chandra Patni

3
@ChandraPatni, Atom öldü . Daha iyi örneklere ihtiyacınız var.
Pacerier

16
Atom ölmüş olabilir, ancak örneğin ruhu hâlâ yerinde.
Ashimema

2
201 yanıtıyla ilgili orijinal yorumum daha çok "hey, bir kaynak oluşturmak istediniz, ancak bağlama göre nihai sonuçla ilgilenmediniz veya bu kaynağa yazma erişiminiz var ancak okuma erişiminiz yok. Her ikisinde de durumda, ana koleksiyona dönmeden önce ihtiyacınız olan tek şey, oluşturulan kaynağın URL'sidir. Yaratıldığının kanıtı olarak. " Bunun ötesinde herhangi bir şey, esasen 200 yanıt gibi görünüyor. RFC'nin aklında başka bir şey olmadığı sürece.
Anthony

50

Birkaç kelimeyle:

  • 200 , bir nesne oluşturulduğunda ve döndürüldüğünde
  • 201 bir nesne oluşturulduğunda ancak yalnızca referansı döndürüldüğünde (kimlik veya bağlantı gibi)

Bunun kaynağı mı?
sudo soul


3
Tools.ietf.org/html/rfc7231#section-6.3.1'i okuduktan sonra , bu anlayışa katılıyorum - sanırım daha çok buna nasıl vardığınızı soruyordum. Ama şimdi anladığım kadarıyla ... 200 = kaynak yaratıldı ve geri gönderildi | 201 = kaynak oluşturuldu ve başvuru döndürüldü | 204 = kaynak oluşturuldu ve yük geri verilmedi
sudo soul

34

Check out HTTP: Yöntem Tanımlar: POST .

POST yöntemi tarafından gerçekleştirilen eylem, bir URI tarafından tanımlanabilen bir kaynakla sonuçlanmayabilir. Bu durumda, yanıtın sonucu açıklayan bir varlık içerip içermediğine bağlı olarak, 200 (Tamam) veya 204 (İçerik Yok) uygun yanıt durumudur.

Kaynak sunucuda bir kaynak yaratılmışsa, yanıt 201 (Oluşturuldu) OLMALIDIR ve talebin durumunu açıklayan ve yeni kaynağa atıfta bulunan bir varlık ve bir Konum başlığı (bkz. Bölüm 14.30).


18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

Bu yalnızca iki nokta üst üste ile ayrılmış anahtar / değer çiftidir.

ETag: "xyzzy"

Herhangi bir tür metin verisi olabilir - Genellikle oluşturulan öğenin tanımlayıcısıyla birlikte bir JSON dizesi eklerim. Tek başına test etme kolaylığı, dahil etmeyi değerli kılar.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

Bu örnekte, oluşturulan öğenin tanımlayıcısı, uri'si ve türü "kaynak özellikleri ve konumdur".


3
Bir ETag'ın , kaynak özelliklerinin ve konumların bir listesini içeren bir varlığa karşılık geldiğini söylüyorsunuz . Önerinizin iyi olduğunu görebiliyorum, test konusundaki düşüncenize çok katılıyorum. Ancak bunun "kaynak özellikleri ve konumlarının bir listesi" ile nasıl örtüştüğünü anlamıyorum.
djna

"Kaynak özellikleri ve konumlarının listesi", sağlanan veri yapısının içeriği olacaktır. JSON yapısının kaynak uri'sini ve belki de yaratılan kaynak türünü içermesi daha katı bir uygulama olacaktır. Cevabı bu şekilde ayarlayacağım.
tempire

7
İnsanların öğrenebilmesi için sorunları belirtin. Aksi takdirde, yorum sadece el sallamaktır.
2013

@SimonGibbs Ne sorunları?
MEMark

2
Spesifikasyonlara göre kesinlikle doğru olsa da, oldukça sıra dışı bir uygulama seçeneği önerir. Ayrıca sayfanın üst kısmındaki soruyu yanıtlamaz (veya bunu ETag ve varlık kelimelerini karıştırarak yapar). 43 oyla cevap muhtemelen daha iyidir.
Simon Gibbs

1

Çıktı aslında talep edilen içerik türüne bağlıdır. Ancak, yaratılan kaynağı en azından Konum'a koymalısınız. Tıpkı Yönlendirme Sonrası-Alma kalıbı gibi.

Benim durumumda, aksi talep edilene kadar boş bırakıyorum. Response.created () kullanılırken JAX-RS davranışı bu olduğundan.

Ancak, Angular gibi tarayıcıların ve çerçevelerin 201'leri otomatik olarak takip etmediğini unutmayın. Davranışı http://www.trajano.net/2013/05/201-created-with-angular-resource/ adresinde not ettim.


-2

Bunun için alacağım bir başka cevap da pragmatik bir yaklaşım benimsemek ve REST API sözleşmenizi basit tutmak olacaktır . Benim durumumda, JavaScript veya XHR'ye başvurmadan işleri daha test edilebilir hale getirmek için REST API'mi yeniden düzenledim, sadece basit HTML formları ve bağlantıları.

Bu nedenle, yukarıdaki sorunuzla ilgili daha spesifik olmak gerekirse, sadece dönüş kodunu kullanırım 200ve döndürülen mesajın uygulamanızın anlayabileceği bir JSON mesajı içermesini isterim. İhtiyaçlarınıza bağlı olarak, web uygulamasının verileri başka bir çağrıda alabilmesi için yeni oluşturulan nesnenin kimliğini gerektirebilir.

Bir not, yeniden düzenlenen API sözleşmemde POST yanıtları önbelleğe alınabilir veri içermemelidir, çünkü POST'lar gerçekten önbelleğe alınamaz, bu nedenle bunları bir GET isteği kullanılarak istenebilecek ve önbelleğe alınabilecek kimliklerle sınırlandırın.

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.