Uygulama düzeyinde olayları tanımlamak için HTTP durum kodları kullanmalı mıyım?


54

Ele aldığım birkaç sunucu, istemcinin bir başarısızlık olarak değerlendirmesi gereken talepler için HTTP 200'ü döndürür, vücutta 'başarı: yanlış' gibi bir şey olur.

Bu, özellikle başarısız kimlik doğrulama durumlarında bana HTTP kodlarının uygun bir şekilde uygulanması gibi gözükmüyor. '4xx' isteğin değiştirilinceye kadar tekrar yapılmaması gerektiğini belirtirken, '5xx' isteğin geçerli olabileceğini veya yeniden denenebileceğini ancak başarısız olduğunu belirtirken, özetle özetlenen HTTP hata kodlarını okudum. Bu durumda 200: oturum açma başarısız oldu veya 200: bu dosyayı bulamadı ya da 200: eksik parametre x, kesinlikle yanlış görünüyor.

Öte yandan, '4xx’in sadece istekle ilgili yapısal bir sorunu göstermesi gerektiği iddiasını görebiliyorum. Bu yüzden, 200'ü geri göndermek uygundur: 401 yetkisiz kullanıcı / şifre yerine izinsizdir, çünkü müşterinin talepte bulunmasına izin verilir, ancak yanlış olur. Bu argüman, eğer sunucu isteği işleme koyabildiyse ve bir karar verebiliyorsa, cevap kodu 200 olmalı ve daha fazla bilgi için gövdeyi kontrol etmek müşteriye kalmıştır.

Temel olarak, bu bir tercih meselesi gibi görünüyor. Ama bu tatmin edici değil, bu yüzden herhangi birinin bu paradigmalardan birinin daha doğru olmasının bir sebebi varsa bilmek isterim.


9
success: falseisteğin başarısız olduğu ve bunu bildiğiniz anlamına gelir. 500 olmalı. Kötü kullanıcı adınız / şifreniz gibi bir şey 401 olurdu. Bu belirsiz değil.
Pete


4
Bu, bence dini savaşları başlatabilen sorulardan biri. Bir RESTful API için cevap açıktır, ancak HTTP'nin yalnızca bir taşıma katmanı olarak değerlendirildiği başka API türleri de vardır ve bu durumlarda uygulama hataları bu katmana taşmamalıdır.
Robotu

5
Hangi http durumunun geri döndürüleceğinden tam olarak emin olmadığımda, her zaman 418 "Ben bir demlik oluyorum" ile baştan çıkarmaya cazip geliyor.
joshp

1
Bir örnek, birden çok (toplu) istek ve yanıttır . Dozajlama dinlendirici bir şey değildir; ancak pratik verimlilik kaygıları, zerafet kaygıları üzerinde yoğunlaşmak için bir miktar destek gerektirmektedir.
saat

Yanıtlar:


35

İlginç soru.

Temel olarak, OSI katmanlarına benzer şeyleri sınıflandırmak için bunu doğru şekilde azaltabiliriz. HTTP, genellikle Uygulama Seviyesi protokolü olarak tanımlanır ve HTTP gerçekten de genel bir İstemci / Sunucu protokolüdür.

Bununla birlikte, uygulamada, sunucu hemen hemen her zaman bir aktarma aygıtıdır ve istemci, içeriği yorumlamaktan ve oluşturmaktan sorumlu olan bir web tarayıcısıdır: Sunucu, işleri yalnızca rastgele bir uygulamaya iletir ve uygulamalar, tarayıcının istediği komut dosyalarını geri gönderir. yürütmekten sorumludur. HTTP etkileşiminin kendisi - istek / yanıt formları, durum kodları, vb. - çoğunlukla, rastgele içeriğin mümkün olduğunca verimli bir şekilde talep edilmeden nasıl sunulacağını, sunulmasını ve sunulmasını ilgilendirmez. Durum kodlarının ve başlıklarının çoğu gerçekten bu amaçlar için tasarlanmıştır.

Uygulamaya özgü akışları işlemek için HTTP protokolünü gizlemeye çalışmakla ilgili sorun, şu iki seçenekten biriyle kalmanızdır: 1) İsteğiniz / yanıt mantığınızı HTTP kurallarının bir alt kümesi yapmalısınız; veya 2) Belli kuralları tekrar kullanmalısınız ve endişelerin ayrılması bulanıklaşmaya meyillidir. Bu ilk bakışta güzel ve temiz görünebilir, ancak bence projeniz ilerledikçe pişmanlık duyduğunuz tasarım kararlarından biri.

Bu nedenle, protokollerin ayrılması konusunda açık olmanın daha iyi olacağını söyleyebilirim. HTTP sunucusu ve web tarayıcısı kendi şey yapalım ve uygulama yapalım onun kendi şey. Uygulamanın talepte bulunabilmesi gerekir ve cevaplara ihtiyacı vardır - ve nasıl talep edileceği, cevapları nasıl yorumlayacağına dair mantığı, HTTP perspektifinden daha karmaşık (veya daha az) olabilir.

Bahsedilmeye değer olan bu yaklaşımın bir başka yararı da, uygulamaların, genel olarak konuşursak, temel bir taşıma protokolüne (mantıksal bir bakış açısıyla) bağlı olmaması gerektiğidir. HTTP geçmişte değişti ve şimdi SPDY'yi izleyen HTTP 2'yi başlattık. Uygulamanızı bir HTTP işlevsellik eklentisinden başka bir şey olarak görmüyorsanız, yeni altyapılar devreye girdiğinde oraya sıkışmış olabilirsiniz.


8
Çok anlayışlı. Buradaki en güçlü argüman, HTTP durum kodları ile uygulamanızın dönüş değerleri arasındaki (empedans) uyumsuzluğudur. Bu uzun vadede bir kabus olabilir. Dahası, taşıma (HTTP) ile taşıma yükü (uygulama verileri) arasındaki endişelerin ayrılmasını büyük ölçüde destekliyorum. Bir hizmet bitiş noktasının URL'sini yanlış yazarsanız, 404 elde edersiniz. Hizmetten varolmayan bir öğeyi sorarsanız, uygulamaya özel bir mesaj alırsınız (belki de sorunu çözmek için kullanabileceğiniz ek bilgilerle).

2
URL’yi yanlış yazarsanız, doğru sunucuya bile girmeyebilirsiniz ve daha sonra her şey olabilir.
gnasher729

Bu hoş bir nüanslı bakış. Bence HTTP'nin sahte bir taşıma katmanı haline gelmesi, bir karar vermenin asıl sorunu olduğunu düşünüyorum. Proxy, bir nodejs sunucusunu proxy'ye atan bir nginx veya apache sunucunuz olduğunda, proxy'nin bu kodları göndermek için zaten kuralları olan ve kendi sorusunun arka uç için standarda uygun olup olmadığına karar verdiğimde kendime rastlarım. Bu gibi durumlarda bazılarında bir tasarım sebep olabilir değil nginx olarak tefsir edebilir, çünkü bir hata kodu göndermek için 'arka uç aşağı.'
Kagan Mattson

4
Katılıyorum. HTTP 200 yanıtında bildirilen bir uygulama katmanı hatasıyla ilgili yanlış bir şey yoktur. 200, HTTP isteğinin / yanıtının kendisinin başarılı olduğunu, içeriğinde ya da o anda çağrılan uygulama katmanı anlambiliminde hiçbir şey söylemeden başarılı olduğunu belirtir.
Monica

22

Bu soru biraz görüş üzerine kuruludur, ancak iki şekilde de.

Gördüğüm gibi, 200 "yumuşak hatalara" hizmet edebilir. API oluşturmaya gelince, bunlar ile "sert hatalar" arasında ayrım yapmaya çalışıyorum.

"Yumuşak hatalar" 200 durum koduyla sunulacak, ancak bir hata açıklaması ve başarı durumu içerecektir false. "Yumuşak hatalar" yalnızca sonuç "beklendiği gibi" olduğunda gerçekleşir, ancak kesin anlamda başarılı olmaz.

"Yumuşak hataların" uygulayıcı için daha fazla ipucu olduğuna dikkat etmek önemlidir . Bu nedenle, insan tarafından okunabilir bir hata mesajı ve / veya son kullanıcıya geri bildirimde bulunmak için kullanılabilecek bir tür kod gibi hata hakkında daha fazla bilgi vermek önemlidir . Bu hatalar uygulayıcıya (ve son kullanıcıya) olayların sunucu tarafında olanlarla ilgili daha fazla bilgi sağlar .

Örneğin, arama işlevine sahip bir API’niz olduğunu ancak arama sırasında hiçbir sonuç alınmadığını varsayalım. Bu hatalı değil, ancak tanımı kesin anlamıyla değil, "başarı" da değil.

JSON olarak biçimlendirilmiş örnek:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

Öte yandan "sert hatalar" , hata için önerilen durum koduyla birlikte sunulacaktır. Kullanıcı oturum açmamış mı? - 403 / 401. Yanlış biçimlendirilmiş giriş? - 400. Sunucu hatası? - 50X. Ve bunun gibi.

Yine, biraz fikir tabanlı. Bazı insanlar tüm hataları eşit, her şeyi "zor hata" olarak ele almak ister. Arama sonucu bulunamadı? Bu bir 404! Madalyonun diğer tarafında, arama sonucu yok mu? - Bu beklendiği gibi, hata yok.

Dikkate alınması gereken bir diğer önemli faktör, mimarlığınızdır; API'nizle JavaScript XHR isteklerini ve jQuery veya AngularJS'yi kullanarak etkileşimde bulunuyorsanız. Bu "sert hatalar" ayrı bir geri çağırma ile ele alınacak, oysa "yumuşak hatalar" geri çağırma "başarısı" ile ele alınabilir. Hiçbir şeyi kırmamak, sonuç hala "beklendiği gibi". Müşteri tarafı kodu daha sonra başarı durumuna ve koduna (veya mesajına) bakabilir. Ve bunu son kullanıcıya yazdır.


2
Aslında, bunun API düzeyinde bir hata olarak sınıflandırılması ilginç bir karardır. Müşteri kendi takdirine bağlı olarak kullanıcı düzeyinde beklenmeyen olarak sınıflandırmasına rağmen.
Deduplicator

1
Faktoring yapılması gereken birçok şey var. Hepsi API uygulamasına bağlıdır. Yine, biraz fikir temelli ve ayrıca API'nin "başarı" ve / veya "hata" olarak tanımladığı şeyden aşağıya. "success": false-Flag bir daha fazlasıdır ipucu birşeyler olduğunu uygulayıcısı için. Genellikle bir dahili durum kodu ile gitmelidir . Ya "code": "NORESULTS"da sayısal bir kod - API'nin yaratıcısı ne olursa olsun. Çoğunlukla oradadır, böylece API'yi uygulayan kişi, sunucuda olanlarla ilgili bilgileri düşürebilir.
maus

15

Bir API'nin iki yönü vardır: API'yi uygulama çabası ve tüm istemcilerin API'yi doğru kullanma çabası.

Müşterinin yazarı olarak, bir web sunucusuna bir istek gönderdiğimde, bir hata (sunucuya hiç doğru şekilde konuşmadım) veya durum koduyla bir cevap alabileceğimi biliyorum. Hataları ele almalıyım. İyi bir cevap vermem gerekiyor. Beklenen, belgelenmiş, "kötü" yanıtları ele almalıyım. Geri kalan her neyse onu ele almalıyım.

API'yi tasarlarken, müşterinin işlemesi için en kolay olana bakmalısınız. Müşteri iyi biçimlendirilmiş bir istek gönderirse ve isteğin sizden istediği şeyi yapabilirseniz, o zaman 200 aralığında bir yanıt vermelisiniz (bu aralıktaki 200'den farklı bir sayının uygun olduğu bazı durumlar vardır).

Müşteri "... gibi tüm kayıtları bana verir" diye sorarsa ve sıfır varsa, başarılı olan bir 200 ve sıfır kayıt dizisi tamamen uygundur. Bahsettiğiniz davalar:

"Giriş başarısız" genellikle 401 olmalıdır. "Dosya bulunamadı" 404 olmalı. "Eksik parametre x" 500 civarında bir şey olmalı (aslında, sunucunun isteğinin kötü olduğunu tespit etmesi durumunda 400, ve 500 Sunucu isteğimle tamamen karıştıysa ve ne olduğu hakkında hiçbir fikri yoksa). Bu durumda 200'e geri dönmek anlamsızdır. Sadece bir müşterinin yazarı demek, sadece durum koduna bakamıyorum, cevabı da çalışmak zorundayım. "Durum 200, harika, işte veriler" diyemiyorum.

Özellikle "parametre eksik" - bu benim başa çıkabileceğim bir şey değil . İsteğim yanlış. İsteğim yanlışsa, bu yanlış isteği düzeltmek için geri dönüşüm yok - başlamak için doğru bir istek gönderirdim. Şimdi bununla başa çıkmak zorundayım. 200 alıyorum ve bir cevap "parametresi eksik" olup olmadığını kontrol etmek zorundayım. Bu korkunç.

Sonunda, birçok farklı durumla başa çıkmak için bir düzine veya iki durum kodu vardır ve bunları kullanmanız gerekir.


3
Bir API'ye bağlanırken, kişisel olarak geçerli bir son noktaya bağlanırken 'bulunamayan' bir dosyaya 200 girmeyi tercih ederim, çünkü HTTP işlememin API'yi işleyen katmana sızması gerekmiyor.
whatsisname,

4
"Eksik parametre x" 400 BAD_REQUEST olmalıdır, çünkü istemci yanlış bir şeyler yapıyordur. Sunucunun yanlış yaptığı durumlar için 500 INTERNAL_SERVER_ERROR ayrılmış olmalıdır. 500, müşterinin tekrar deneyebileceğini ima eder. 400, birisinin müşteriyi düzeltmesi gerektiğine işaret ediyor.
Robotu

1
RESTful bir arayüz yazıyorsanız, URL belirli bir nesneyi tanımlar ve bu nedenle 404 uygundur. Kavramsal olarak aynıdır /customers/premium/johndoe.json, veritabanında olmayan bir müşteriye /files/morefiles/customers.htmlve dosya sisteminde olmayan bir sayfaya atıfta bulunur.
Robotu

@whatsisname Söyledikleriniz mantıklı çünkü o zaman kötü olan veya kaynak bulunmayan son nokta ise belirsizdir. Ayrıca, bitiş noktasının geçerli olup olmadığını, bu adreste hiçbir kaynak bulunmadığını ve bu nedenle 404her iki durumda da a'nın doğru olduğunu iddia edebilirsiniz .
Pete

2
Bahsetmediğim bir şey, uygulama hatalarını HTTP durum kodları üzerinde attığınızda bilgileri kaybedebileceğinizdir. Uygulama yalnızca bir 404 döndürürse veya başka bir şey döndürmezse, uygulamanızın bir 404 döndürdüğü veya sunucunun dosyayı bulamadığı için olduğunu bilmiyorsunuz. Bu, hata ayıklama işleminize bir adım daha ekleyebilir.
AmadeusDrZaius
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.