Kody stanu REST HTTP dla nieudanej weryfikacji lub nieprawidłowego duplikatu

825

Tworzę aplikację z interfejsem API opartym na REST i doszedłem do momentu, w którym określam kody stanu dla każdego żądania.

Jaki kod stanu powinienem wysłać w przypadku wniosków, które nie sprawdzają poprawności lub w przypadku, gdy żądanie próbuje dodać duplikat do mojej bazy danych?

Przejrzałem http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html, ale żaden z nich nie wydaje się odpowiedni.

Czy istnieje powszechna praktyka podczas wysyłania kodów stanu?

alexn
źródło

Odpowiedzi:

779

W przypadku niepowodzenia sprawdzania poprawności danych wejściowych: 400 Błędne żądanie + opcjonalny opis. Jest to sugerowane w książce „ RESTful Web Services ”. W przypadku podwójnego zgłoszenia: 409 Konflikt


Aktualizacja z czerwca 2014 r

Odpowiednią specyfikacją był RFC2616 , który dawał użycie 400 (Bad Request) raczej wąsko jako

Serwer nie mógł zrozumieć żądania z powodu nieprawidłowej składni

Więc to może być twierdził, że to było niewłaściwe błędów semantycznych. Ale już nie; od czerwca 2014 r. odpowiednia norma RFC 7231 , która zastępuje poprzednią RFC2616, daje szersze zastosowanie 400 (Złe żądanie) jako

serwer nie może lub nie przetworzy żądania z powodu czegoś, co jest postrzegane jako błąd klienta

deamon
źródło
3
Tak, treść żądania jest częścią składni.
deamon
62
Złe żądanie jest zdecydowanie najczęstszą odpowiedzią na tego rodzaju problem. Jedyną inną alternatywą jest 422 jednostka nieprzetworzona. W rzeczywistości pochodzi z WebDav, ale ponowne użycie dowolnego kodu statusu zarejestrowanego w IANA jest całkowicie poprawne.
Darrel Miller
19
Jak zatem odróżnić zniekształcone dane, których serwer nie może nawet przeanalizować, i błąd sprawdzania poprawności? Klient obsługiwałby te dwie odpowiedzi zupełnie inaczej. W celu weryfikacji prawdopodobnie wyświetlą błędy użytkownikowi. W przypadku naprawdę „zniekształconych danych” rejestrują błąd, aby błąd w metodzie generującej żądanie mógł zostać naprawiony.
Josh Noe,
18
Nie zgadzam się z twoją interpretacją RFC7231, chociaż stwierdza something perceived to be a client error, że wszystkie przykłady podane w tym akapicie są naruszeniem protokołu HTTP, a nie błędami logicznymi: składnią, ramką, routingiem. Dlatego uważam, że specyfikacja HTTP nie zezwala na 400 nieudanych operacji sprawdzania poprawności na poziomie aplikacji.
Dima Tisnek
2
dlaczego nie użyć jednostki 422 - nieprzetworzonej? Wydaje mi się to bardziej logiczne
java_geek
278
  • Sprawdzanie poprawności nie powiodło się: 403 Zabronione („Serwer zrozumiał żądanie, ale odmawia jego spełnienia”). Wbrew powszechnej opinii RFC2616 nie mówi „403 jest przeznaczone tylko do nieudanego uwierzytelnienia”, ale „403: Wiem, czego chcesz, ale tego nie zrobię”. Ten warunek może, ale nie musi, wynikać z uwierzytelnienia.
  • Próba dodania duplikatu: 409 Konflikt („Żądanie nie mogło zostać zakończone z powodu konfliktu z bieżącym stanem zasobu.”)

Zdecydowanie powinieneś podać bardziej szczegółowe wyjaśnienie w nagłówkach odpowiedzi i / lub treści (np. Z niestandardowym nagłówkiem - X-Status-Reason: Validation failed).

Piskvor opuścił budynek
źródło
17
@deamon: To nie jest specyfikacja, to Wikipedia, czyli czyjaś opinia na temat „co oznaczają kody stanu HTTP”; zwróć uwagę, że strona w zasadzie mówi „to właśnie oznacza Apache z 403, to właśnie IIS oznacza z 403” i nigdzie nie odnosi się do oficjalnej RFC. Wygląda na to, że powtarzasz „403 oznacza to, co mówi Apache”. NIE. Rzeczywisty RFC (który jest odpowiednim dokumentem, nie implementacja Apache, nie implementacja IIS, implementacja nikogo innego) jest tutaj: w3.org/Protocols/rfc2616/rfc2616-sec10.html
Piskvor opuścił budynek
57
„10.4.4 403 Zabronione Serwer zrozumiał żądanie, ale odmawia jego spełnienia. Autoryzacja nie pomoże i NIE POWINIEN się powtórzyć. Jeśli metoda żądania nie była HEAD, a serwer chce podać do publicznej wiadomości, dlaczego żądanie nie spełnione, POWINIEN opisywać powód odmowy w jednostce. Jeśli serwer nie chce udostępnić tych informacji klientowi, zamiast tego można użyć kodu stanu 404 (Nie znaleziono). ” Nie widzę tam żadnego podkreślenia („POWINNY / NIE POWINNY” to słowa kluczowe RFC 2119, a nie wyróżnienie); to twój pomysł, co oznacza „zabronione”, a nie RFC.
Piskvor opuścił budynek
10
Podoba mi się ta odpowiedź, ale wciąż widzę jeden mały problem. Zgodnie ze specyfikacją , gdy zwracany jest kod 403 , „NIE POWINIEN się powtarzać”. Jednak zwracanie wartości 409 „jest dozwolone tylko w sytuacjach, w których oczekuje się, że użytkownik będzie w stanie rozwiązać konflikt i ponownie przesłać żądanie”. W przypadku duplikatu uważam, że 403 jest bardziej odpowiednie, ponieważ nie można tak naprawdę rozwiązać konfliktu (z wyjątkiem usunięcia poprzedniej instancji zasobu).
pablobm
2
W przypadku samego komunikatu o błędzie należy zmodyfikować frazę przyczyny, więc wysłanie nagłówka HTTP/1.0 403 Form validation errorsjest najczystszym sposobem.
aleemb
6
IMO, 422 „Nieprzetworzona jednostka” ma znacznie większy sens. Moje rozumowanie jest takie, że nie chodzi o to, że serwer odmawia wykonania żądania, ale o to, że serwer nie może spełnić żądania.
tybro0103,
225

Polecam kod statusu 422 „Podmiot nieprzetworzony” .

11.2 422 Podmiot nieprzetworzony

Kod statusu 422 (Unprocessable Entity) oznacza, że ​​serwer rozumie typ treści encji żądania (stąd kod statusu 415 (Unsupported Media Type) jest nieodpowiedni), a składnia encji żądania jest poprawna (a więc 400 (Bad Request ) kod stanu jest nieodpowiedni), ale nie mógł przetworzyć zawartych instrukcji. Na przykład ten warunek błędu może wystąpić, jeśli treść żądania XML zawiera dobrze sformułowane (tj. Poprawne składniowo), ale semantycznie błędne instrukcje XML.

Julian Reschke
źródło
11
Oczywiście jest to kod stanu HTTP, patrz iana.org/assignments/http-status-codes . Istnieje więcej kodów statusu niż te zdefiniowane w RFC 2616.
Julian Reschke
7
WebDAV to rozszerzenie HTTP . „Rozszerzenia HTTP dla rozproszonego tworzenia i wersjonowania w sieci (WebDAV)” Zatem kod stanu 422 nie jest kodem stanu HTTP, ale kodem stanu rozszerzenia http.
deamon
16
deamon, to nie ma sensu. HTTP określa sposób definiowania nowych kodów i właśnie to robi WebDAV. Z jakiegoś powodu istnieje rejestr kodów stanu.
Julian Reschke,
14
FYI - RFC opis 422: 11.2. 422 Nieprzetworzona jednostka Kod stanu 422 (Nieprzetworzona jednostka) oznacza, że ​​serwer rozumie typ zawartości encji żądania (stąd kod statusu 415 (Nieobsługiwany typ nośnika) jest nieodpowiedni), a składnia encji żądania jest poprawna (a więc 400 Kod statusu (Błędne żądanie) jest nieodpowiedni), ale nie mógł przetworzyć zawartych instrukcji. Na przykład ten warunek błędu może wystąpić, jeśli treść żądania XML zawiera dobrze sformułowane (tj. Poprawne składniowo), ale semantycznie błędne instrukcje XML.
Steve Kallestad
6
Wątki nie wygasają. Muszą być utrzymywane, bo najlepsze wyniki wyszukiwania Google zaczynają być niedokładne.
James Billingham
81

200,300, 400, 500 są bardzo ogólne. Jeśli chcesz ogólny, 400 jest OK.

422 jest używany przez rosnącą liczbę interfejsów API, a nawet jest używany przez Railsy po wyjęciu z pudełka.

Bez względu na to, jaki kod stanu wybierzesz dla swojego interfejsu API, ktoś się nie zgodzi. Ale wolę 422, ponieważ „400 + status tekstowy” uważam za zbyt ogólny. Ponadto nie korzystasz z parsera zgodnego z JSON; przeciwnie, 422 z odpowiedzią JSON jest bardzo wyraźny i można przekazać wiele informacji o błędach.

Mówiąc o odpowiedzi JSON, mam tendencję do standaryzacji odpowiedzi na błąd Railsów w tym przypadku, która jest:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

Ten format jest idealny do sprawdzania poprawności formularza, który uważam za najbardziej skomplikowany przypadek do obsługi pod względem „bogactwa raportowania błędów”. Jeśli twoja struktura błędów jest taka, prawdopodobnie obsłuży wszystkie potrzeby związane z raportowaniem błędów.

sethcall
źródło
2
Co z błędami wynikającymi z interakcji między argumentami. Oznacza to, że arg1jest poprawny i arg2prawidłowy, ale połączenie tych dwóch z przesłanymi konkretnymi wartościami jest nieprawidłowe.
Jonasz
1
Nie zastanawiałbym się nad tym; po prostu wybierz taki, który wydaje się być właścicielem relacji.
sethcall
lub nawet po prostu błąd na obu argumentach. Myślę, że jako użytkownik chciałbym zobaczyć błąd w każdym z konfliktowych pól.
tuli się
Miły!. wyraźne jest lepsze niż niejawne
bhathiya-perera
46

200

Ugh ... (309, 400, 403, 409, 415, 422) ... wiele odpowiedzi próbuje zgadnąć, argumentować i ustandaryzować najlepszy kod powrotu dla udanego żądania HTTP, ale nieudane wywołanie REST .

Jest źle mieszać kody stanu HTTP i kody stanu spoczynku.

Widziałem jednak wiele implementacji mieszających je i wielu programistów może się ze mną nie zgodzić.

Kody zwrotne HTTP są powiązane z samym HTTP Requestsobą. Wywołanie REST jest wykonywane przy użyciu żądania protokołu przesyłania hipertekstu i działa na niższym poziomie niż sama wywołana metoda REST. REST jest koncepcją / podejściem, a jego wynik jest wynikiem biznesowym / logicznym , podczas gdy kod wyniku HTTP to transportowym .

Na przykład zwracanie „404 Nie znaleziono”, gdy dzwonisz / users /, jest mylące, ponieważ może to oznaczać:

  • Niepoprawny identyfikator URI (HTTP)
  • Nie znaleziono użytkowników (REST)

„403 Zabroniony / Odmowa dostępu” może oznaczać:

  • Potrzebne specjalne pozwolenie. Przeglądarki mogą sobie z tym poradzić, pytając użytkownika / hasło. (HTTP)
  • Niepoprawne uprawnienia dostępu skonfigurowane na serwerze. (HTTP)
  • Musisz być uwierzytelniony (REST)

Lista może być kontynuowana z błędem „500 Server error” (błąd rzucenia HTTP Apache / Nginx lub błąd ograniczeń biznesowych w REST) ​​lub innymi błędami HTTP itp.

Na podstawie kodu trudno zrozumieć, co było przyczyną niepowodzenia, awarii HTTP (transportu) lub awarii REST (logicznej).

Jeśli żądanie HTTP zostało fizycznie wykonane pomyślnie, zawsze powinno zwrócić kod 200, niezależnie od tego, czy rekord (y) został znaleziony, czy nie. Ponieważ zasób URI został znaleziony i był obsługiwany przez serwer HTTP. Tak, może zwrócić pusty zestaw. Czy można otrzymać pustą stronę internetową z wynikiem 200 jako HTTP, prawda?

Zamiast tego możesz zwrócić 200 kod HTTP z kilkoma opcjami:

  • obiekt „error” w wyniku JSON, jeśli coś pójdzie nie tak
  • Opróżnij tablicę / obiekt JSON, jeśli nie znaleziono rekordu
  • Flaga wyniku bool / sukces w połączeniu z poprzednimi opcjami dla lepszej obsługi.

Ponadto niektórzy dostawcy Internetu mogą przechwytywać żądania i zwracać kod 404 HTTP. Nie oznacza to, że twoich danych nie znaleziono, ale na poziomie transportu coś jest nie tak.

Z Wiki :

W lipcu 2004 r. Brytyjski dostawca usług telekomunikacyjnych BT Group wdrożył system blokowania treści Cleanfeed, który zwraca błąd 404 w przypadku każdego żądania treści zidentyfikowanych przez Internet Watch Foundation jako potencjalnie nielegalne. W tych samych okolicznościach inni dostawcy usług internetowych zwracają błąd „zabronione” HTTP 403. Praktyka stosowania fałszywych błędów 404 jako sposobu na ukrycie cenzury została również zgłoszona w Tajlandii i Tunezji. W Tunezji, gdzie przed rewolucją w 2011 r. Cenzura była poważna, ludzie zdali sobie sprawę z natury fałszywych błędów 404 i stworzyli wymyśloną postać o imieniu „Ammar 404”, która reprezentuje „niewidzialnego cenzora”.

Dlaczego nie po prostu odpowiedzieć na coś takiego?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

Google zawsze zwraca 200 jako kod stanu w interfejsie API Geokodowania, nawet jeśli żądanie logicznie się nie powiedzie: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook zawsze zwraca 200 za pomyślne żądania HTTP, nawet jeśli żądanie REST nie powiedzie się: https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

To proste, kody stanu HTTP są dla żądań HTTP. Interfejs API REST należy do Ciebie, zdefiniuj kody stanu.

Marcodor
źródło
3
W rzeczywistości używanie kodów stanu HTTP dla REST jest jeszcze bardziej mylące: 1) widzisz 4xx w przyborniku programisty i nie możesz powiedzieć, po prostu zerkając na to, czy serwer zwrócił jakąś sensowną wartość lub w ogóle nie przetworzył twojego żądania a następnie 2) wszystkie procedury obsługi błędów / wyjątków / łapań powinny sprawdzić, który serwer zwrócił w odpowiedzi (przeważnie nie, ponieważ trzeba to robić przy każdym zgłoszeniu serwisowym) i wiele razy 3) otrzymujesz taką samą ładowność ( type) zarówno na ścieżce sukcesu, jak i ścieżki błędu prowadzącej do skomplikowanego / zduplikowanego kodu ... Rzeczywiście bardzo mylące.
szczepanpp
9
Ta odpowiedź myli pierwotną semantykę protokołu HTTP z tym, w jaki sposób REST przez HTTP jako styl architektoniczny zmienia przeznaczenie HTTP do implementacji interfejsów API usług sieciowych. Jako styl architektoniczny REST nie jest standardem, którego należy rygorystycznie przestrzegać, jest to sugerowane podejście. Użycie odpowiedzi 200 w przypadku niepowodzenia sprawdzania poprawności jest niewłaściwe lub niepoprawne, jednak klienci mylą się z odpowiedzią, że żądanie się powiodło, ale w rzeczywistości nie powiodło się z powodu niepowodzenia sprawdzania poprawności, co jest ważnym szczegółem ukrytym w treści odpowiedzi, semantyka, którą klient musi przeanalizować, aby zrozumieć.
Kevin Hooke
5
@Marcodor, jeśli połączenie API nie powiedzie się, ale zwrócisz 200, wskazując powodzenie, jak to dobry pomysł? jest niejasne i mylące dla użytkowników Twojego interfejsu API.
Kevin Hooke
3
Poprawne z wielu powodów, nie tylko z rozdzielenia błędów HTTP a błędów REST. Sprawdzanie poprawności REST często wymaga więcej niuansów. Na przykład rekord został zaakceptowany, ale oznaczony jako duplikat, a odrzucony z powodu naruszenia unikalnego indeksu. Chcesz także spójnego modelu zwrotu. Metoda .NET BadRequest()ma własny model zwrotu, który będzie się różnić od zwykłego modelu zwrotu. To koszmar do przeanalizowania. @KevinHooke, zwracanie HTTP 200 z powodu błędu sprawdzania poprawności REST przypomina powiedzenie: „Otrzymałem wiadomość, odpowiedź brzmi„ nie ”i oto dlaczego. Zwracający HTTP 400 mówi: „Nie wiem o czym mówisz”.
Neil Laslett,
5
argument „bo google to robi, musi mieć rację” jest dla mnie szalony. w porządku jest zakwestionowanie czegoś, co Google zaimplementował dla dzieci. Zwrócenie HTTP 200 w przypadku nieudanego wywołania rest myli osobę wywołującą API, która powinna mieć wartość 4xx, a do treści można dołączyć ładny kod JSON / XML ... zatrzymajmy razem szaleństwo.
Jeryl Cook
43

Duplikatem w bazie danych powinno być 409 CONFLICT.

Polecam używać 422 UNPROCESSABLE ENTITYdo błędów sprawdzania poprawności.

Podaję tutaj dłuższe wyjaśnienie kodów 4xx .

Phil Parker
źródło
6

Kod stanu 304 niezmodyfikowany również dawałby akceptowalną odpowiedź na zduplikowane żądanie. Jest to podobne do przetwarzania nagłówka If-None-Matchprzy użyciu znacznika encji.

Moim zdaniem odpowiedź @ Piskvor jest bardziej oczywistym wyborem na to, co postrzegam, jest intencją pierwotnego pytania, ale mam alternatywę, która jest również istotna.

Jeśli chcesz traktować zduplikowane żądanie jako ostrzeżenie lub powiadomienie, a nie jako błąd, kod stanu odpowiedzi 304Niezmodyfikowany iContent-Location nagłówek identyfikujący istniejący zasób będą równie poprawne. Gdy celem jest jedynie zapewnienie istnienia zasobu, zduplikowane żądanie nie byłoby błędem, ale potwierdzeniem. Żądanie nie jest złe, ale jest po prostu nadmiarowe, a klient może odwoływać się do istniejącego zasobu.

Innymi słowy, żądanie jest dobre, ale ponieważ zasób już istnieje, serwer nie musi wykonywać żadnego dalszego przetwarzania.

Suncat2000
źródło
6
Zrozumiałem, że 304 jest przeznaczony do operacji GET, które pomagają w buforowaniu.
Sinaesthetic,
6

Adapter ActiveRecord Ember-Data oczekuje 422 UNPROCESSABLE ENTITYna zwrot z serwera. Tak więc, jeśli twój klient jest napisany w Ember.js, powinieneś użyć 422. Tylko wtedy DS.Errors zostaną wypełnione zwracanymi błędami. Oczywiście możesz zmienić 422 na dowolny inny kod w adapterze.

Daniel Kmak
źródło