Czy powinienem zwrócić odpowiedź 204 lub 404, gdy nie znaleziono zasobu?

15

Rozwijam prostą usługę RESTful dla turniejów i harmonogramów. Gdy turniej jest tworzony na podstawie żądania POST zawierającego ciało JSON, turniej jest wstawiany do BiMap, zadeklarowanej w następujący sposób w implementacji DAO:

private BiMap<String, Tournament> tournaments = Maps.synchronizedBiMap(HashBiMap.create());

Po utworzeniu turnieju jest zwracany powiązany identyfikator ciągu, aby użytkownik mógł mieć w przyszłości odniesienia do tego turnieju. Może odzyskać informacje z nowego turnieju, wykonując następujące żądanie:

GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39

Ale co, jeśli nie zostanie znaleziony turniej o takim identyfikatorze? Do tej pory zwracam odpowiedź 204. Jersey robi to za mnie, wracając nullz jednej ze swoich metod. Jest to metoda, która odpowiada powyższej trasie:

@Path("/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("id") String id) {
    Optional<Tournament> optTournament = tournamentDao.getTournament(id);
    if (optTournament.isPresent())
        return optTournament.get();
    return null;
}

Moje pytanie brzmi: czy odpowiedź jest w porządku 204: No Content, czy raczej powinna to być 404odpowiedź, ponieważ nie znaleziono zasobu?

Jeśli powinienem zmienić go na 404, oczywiste pytanie: powinienem zmienić podpis metody, prawda? Ponieważ teraz turniej (typu Tournament) może nie zostać zwrócony, metoda powinna wyglądać inaczej. Czy Responsezamiast tego powinienem użyć tego typu jako typu zwrotu?

dabadaba
źródło

Odpowiedzi:

32

HTTP 204oznacza, że coś zostało znalezione, ale jest pusty. Na przykład wyobraź sobie, że podajesz pliki dziennika za pośrednictwem protokołu HTTP z żądaniami takimi jak http://example.com/logs/[date-goes-here] . 18 maja 2015 r .:

  • http://example.com/logs/2015-05-19 zwróci HTTP 404, co oznacza, że ​​nie ma dzienników, ponieważ, cóż, trudno jest zapisywać przyszłość.

  • http://example.com/logs/2015-05-18 zwróci jednak albo HTTP 200wpisy dziennika w treści odpowiedzi, albo HTTP 204jeśli plik dziennika został utworzony, ale nadal nie ma zapisanych dzienników dla tego data.

Jeśli podasz nullramowi jako odpowiedź na żądanie, zakłada się, że znalazłeś wpis, a zatem ten wpis jest pusty HTTP 204. Zamiast tego powinieneś throw new NotFoundException();wskazać frameworkowi, że wpis nie istnieje, aby wygenerował HTTP 404.

Jeśli powinienem zmienić go na 404, oczywiste pytanie: powinienem zmienić podpis metody, prawda?

Nie, ty nie. To miło z tego powodu throw new NotFoundException();. Będzie działać bez względu na faktyczny typ zwracanej metody.

Arseni Mourzenko
źródło
5
Zwróć szczególną uwagę na RFC 2616 . 204 odpowiedzi są zgodne ze specyfikacją tylko wtedy, gdy całkowicie pomijasz treść wiadomości. W pewnym stopniu odpowiedź 204 ma na celu stwierdzenie: „nie, to nie przypadek, że nie zwróciłem żadnej treści”. Aby rozwinąć przykład MainMa: Jeśli narzędzie do wyszukiwania dzienników wyrzuca pliki tekstowe (np. Cienkie opakowanie wokół plików dziennika, które po prostu wyrzuca plik dziennika bez zmian), 204 byłby odpowiedni dla pustego pliku dziennika. Gdyby odpowiedź była pustym obiektem JSON (np. {content: ''}), Odpowiedź 204 byłaby nieodpowiednia.
Brian
ponieważ, cóż, trudno jest rejestrować przyszłość. ” - Ten bit zależy od dowolnej daty; dlaczego nie zrobić z tego czegoś, co nie wymaga od czytelnika udawania, że ​​to nie dzisiaj? Może używanie 2015-02-29byłoby lepsze, ponieważ to randka, która w ogóle nie istnieje?
Pozew funduszu Moniki
1

Twoja prośba to GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39.

Jeśli http://localhost:8080/eventscheduler/nie istnieje jako punkt końcowy, powinieneś zwrócić 404. Próbujesz uzyskać dostęp do zasobu ( /eventscheduler/), który nie istnieje. Oznaczałoby to klientowi, że serwer istnieje localhost:8080, ale nie ma nic w eventschedulerpunkcie końcowym.

Jeśli http://localhost:8080/eventscheduler/istnieje jako punkt końcowy, ale wymagane zasoby są niedostępne, odpowiedni jest błąd 5xx. Dobrym przykładem tego jest sytuacja, gdy baza danych jest w trybie offline, gdzie można zwrócić 503. Oczywiście możesz po prostu zwrócić ogólny błąd 500 zamiast określonej instancji.

Jeśli http://localhost:8080/eventscheduler/istnieje, ale rzecz reprezentowana przez c15268ce-474a-49bd-a623-b0b865386f39nie istnieje, zwróciłbym 200 z ciałem wskazującym szczegóły. Punkt końcowy istnieje, wykonane żądanie było całkowicie poprawne i mogło zostać przetworzone, ale nie znaleziono dopasowania.

Jeśli żądanie klienta do punktu końcowego było nieprawidłowe, sprawdzono by inne błędy 4xx. Możesz wskazać, że klient nie ma uprawnień dostępu do punktu końcowego lub żądanych elementów za pomocą 401 lub 403, lub możesz użyć 400, aby wskazać, że żądanie jest nieprawidłowe. W przypadku dowolnej z nich w treści odpowiedzi można podać dodatkowe informacje.

Thomas Owens
źródło
Nie ma potrzeby rozróżniania punktu końcowego od zasobu. Jeśli identyfikator URI nie pasuje do żadnych zasobów, z jakiegokolwiek powodu, serwer powinien zwrócić 404.
bdsl
Sprawdź kod odpowiedzi na tej stronie, aby zobaczyć przykład prawidłowego działania witryny. To witryna internetowa, a nie interfejs API, ale obowiązuje ta sama specyfikacja http. softwareengineering.stackexchange.com/questions/266183385
bdsl
@bdsl Mogę powiedzieć, że to absolutnie źle. Na przykład korzystam z usługi użytkownika, która może zwrócić profil użytkownika. Powiedzmy, że ten punkt końcowy jest /useri jest używany jak /[email protected]. Jako konsument interfejsu API chcę wiedzieć, czy /userz jakiegoś powodu nie istnieje na serwerze (być może został dodany w wersji 2 interfejsu API, a serwer znajduje się w wersji 1 lub został przemianowany w wersji 3), czy też użytkownik z adresem e-mail [email protected]nie istnieje Pierwszy to 404, drugi to 200 z treścią, która wskazuje, że żaden użytkownik nie ma tego adresu e-mail.
Thomas Owens
@bdsl To miłe, ale to nie znaczy, że jest dobre lub najlepsze. Nie sądzę też, aby można było porównać witrynę internetową zaprojektowaną do interakcji człowieka za pośrednictwem przeglądarki internetowej z interfejsem API zaprojektowanym do użytku w systemie oprogramowania.
Thomas Owens
1
Zagadnienie to jest omówione dalej w youtube.com/watch?v=nSKp2StlS6s
bdsl