Piszę aplikację internetową REST (NetBeans 6.9, JAX-RS, TopLink Essentials) i próbuję zwrócić kod stanu JSON i HTTP. Mam gotowy i działający kod, który zwraca JSON po wywołaniu metody HTTP GET z klienta. Głównie:
@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {
// some code to return JSON ...
return myJson;
}
Ale chcę również zwrócić kod stanu HTTP (500, 200, 204 itd.) Wraz z danymi JSON.
Próbowałem użyć HttpServletResponse
:
response.sendError("error message", 500);
Ale to sprawiło, że przeglądarka pomyślała, że to „prawdziwa” 500, więc wyjściowa strona internetowa była zwykłą stroną błędu HTTP 500.
Chcę zwrócić kod stanu HTTP, aby mój JavaScript mógł obsługiwać logikę w zależności od niego (np. Wyświetlać kod błędu i komunikat na stronie HTML). Czy jest to możliwe, czy nie należy do tego używać kodów stanu HTTP?
java
rest
jax-rs
http-status-codes
Miauczeć
źródło
źródło
Odpowiedzi:
Oto przykład:
Spójrz na odpowiedź klasę .
Pamiętaj, że zawsze powinieneś określać typ zawartości, szczególnie jeśli przekazujesz wiele typów treści, ale jeśli każda wiadomość będzie reprezentowana jako JSON, możesz po prostu dodać adnotację do metody
@Produces("application/json")
źródło
return Response.status(Response.Status.Forbidden).entity(myPOJO).build();
Działa tak, jakbyś chciałreturn myPOJO;
, ale z dodatkowym ustawieniem kodu statusu HTTP.Istnieje kilka przypadków użycia do ustawiania kodów stanu HTTP w usłudze sieciowej REST, a co najmniej jeden nie został wystarczająco udokumentowany w istniejących odpowiedziach (tj. Gdy używasz auto-magicznej serializacji JSON / XML za pomocą JAXB, a chcesz zwrócić obiekt do serializacji, ale także kod stanu inny niż domyślny 200).
Pozwólcie, że spróbuję wyliczyć różne przypadki użycia i rozwiązania dla każdego z nich:
1. Kod błędu (500, 404, ...)
Najczęstszym przypadkiem użycia, gdy chcesz zwrócić kod stanu inny niż w
200 OK
przypadku wystąpienia błędu.Na przykład:
a) Rzuć wyjątek
W takim przypadku uważam, że najczystszym sposobem rozwiązania problemu jest zgłoszenie wyjątku. Ten wyjątek zostanie obsłużony przez
ExceptionMapper
, który przełoży wyjątek na odpowiedź z odpowiednim kodem błędu.Możesz użyć domyślnej,
ExceptionMapper
która jest wstępnie skonfigurowana z Jersey (i myślę, że to samo z innymi implementacjami) i rzucić dowolną z istniejących podklasjavax.ws.rs.WebApplicationException
. Są to wstępnie zdefiniowane typy wyjątków, które są wstępnie mapowane na różne kody błędów, na przykład:Itd. Możesz znaleźć listę tutaj: API
Alternatywnie możesz zdefiniować własne wyjątki i
ExceptionMapper
klasy oraz dodać tych twórców map do Jersey za pomocą@Provider
adnotacji ( źródło tego przykładu ):Dostawca:
Uwaga: możesz także napisać ExceptionMappers dla istniejących typów wyjątków, których używasz.
b) Użyj konstruktora odpowiedzi
Innym sposobem ustawienia kodu stanu jest użycie
Response
konstruktora do zbudowania odpowiedzi za pomocą zamierzonego kodu.W takim przypadku typem zwracanym przez metodę musi być
javax.ws.rs.core.Response
. Jest to opisane w różnych innych odpowiedziach, takich jak zaakceptowana odpowiedź hisdrewness i wygląda następująco:2. Sukces, ale nie 200
Innym przypadkiem, w którym chcesz ustawić status zwrotu, jest operacja zakończona powodzeniem, ale chcesz zwrócić kod powodzenia inny niż 200 wraz z treścią zwracaną w treści.
Częstym przypadkiem jest sytuacja, gdy tworzysz nową jednostkę (
POST
żądanie) i chcesz zwrócić informacje o tej nowej jednostce lub może samej jednostce, wraz z201 Created
kodem statusu.Jednym z podejść jest użycie obiektu odpowiedzi tak jak opisano powyżej i samodzielne ustawienie treści żądania. Jednak w ten sposób tracisz możliwość korzystania z automatycznej serializacji do XML lub JSON zapewnianej przez JAXB.
To jest oryginalna metoda zwracająca obiekt encji, który zostanie zserializowany do JSON przez JAXB:
Zwróci to reprezentację JSON nowo utworzonego użytkownika, ale zwróci status 200, a nie 201.
Problem polega na tym, że jeśli chcę użyć
Response
konstruktora do ustawienia kodu powrotu, muszę zwrócićResponse
obiekt w mojej metodzie. Jak nadal zwracaćUser
obiekt do serializacji?a) Ustaw kod w odpowiedzi serwletu
Jednym ze sposobów rozwiązania tego problemu jest uzyskanie obiektu żądania serwletu i samodzielne ustawienie kodu odpowiedzi, jak pokazano w odpowiedzi Garetta Wilsona:
Metoda nadal zwraca obiekt encji, a kod stanu będzie wynosił 201.
Zauważ, że aby zadziałało, musiałem opróżnić odpowiedź. Jest to nieprzyjemne odrodzenie niskiego poziomu kodu API serwletów w naszym ładnym zasobie JAX_RS, a co gorsza, powoduje to, że nagłówki są niemodyfikowalne po tym, ponieważ zostały już wysłane na drut.
b) Użyj obiektu odpowiedzi z bytem
W takim przypadku najlepszym rozwiązaniem jest użycie obiektu Response i ustawienie encji do serializacji na tym obiekcie odpowiedzi. Byłoby miło, gdyby obiekt Response był ogólny, aby wskazywał typ jednostki ładunku w tym przypadku, ale nie jest tak obecnie.
W takim przypadku używamy utworzonej metody klasy konstruktora odpowiedzi, aby ustawić kod statusu na 201. Przekazujemy obiekt encji (użytkownika) do odpowiedzi za pomocą metody encji ().
Rezultat jest taki, że kod HTTP to 401, tak jak chcieliśmy, a treść odpowiedzi jest dokładnie taka sama jak JSON, jak poprzednio, gdy zwracaliśmy obiekt User. Dodaje także nagłówek lokalizacji.
Klasa Response ma wiele metod konstruktora dla różnych statusów (stati?), Takich jak:
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
Uwaga: obiekt hateoas to klasa pomocnicza, którą opracowałem, aby pomóc w generowaniu identyfikatorów URI zasobów. Musisz wymyślić tutaj swój własny mechanizm;)
O to chodzi.
Mam nadzieję, że ta długa odpowiedź pomoże komuś :)
źródło
flush
jest naprawdę brudne.Odpowiedź od jego zagłady zadziała, ale modyfikuje całe podejście do umożliwienia dostawcy, np. Jackson + JAXB, automatycznej konwersji zwróconego obiektu na jakiś format wyjściowy, taki jak JSON. Zainspirowany postem Apache CXF (który wykorzystuje klasę specyficzną dla CXF) znalazłem jeden sposób na ustawienie kodu odpowiedzi, który powinien działać w dowolnej implementacji JAX-RS: wstrzyknięcie kontekstu HttpServletResponse i ręczne ustawienie kodu odpowiedzi. Na przykład oto, jak ustawić kod odpowiedzi,
CREATED
gdy jest to właściwe.Ulepszenie: po znalezieniu innej pokrewnej odpowiedzi dowiedziałem się, że można wstrzyknąć
HttpServletResponse
zmienną składową, nawet dla klasy usługi singleton (przynajmniej w RESTEasy) !! Jest to znacznie lepsze podejście niż zanieczyszczenie interfejsu API szczegółami implementacji. Wyglądałoby to tak:źródło
@Produces
i nie określać typu nośnika w końcowej wersjiResponse.ok
, a otrzymany obiekt zwrotny zostanie poprawnie zserializowany do JAXB w odpowiednim typie nośnika, aby pasował do żądania. (Właśnie próbowałem tego z jedną metodą, która mogłaby zwrócić albo XML, albo JSON: sama metoda też nie musi o tym wspominać, z wyjątkiem@Produces
adnotacji.)MessageBodyWriter
aProvider
pozwala na niejawne negocjowanie treści, chociaż wydaje się, że w twoim przykładzie brakuje jakiegoś kodu. Oto kolejna odpowiedź, którąresponse.setStatus()
. Jedynym sposobem wysłania na przykład odpowiedzi 404 „Nie znaleziono” jest ustawienie kodu statusu odpowiedziresponse.setStatus(404)
en, a następnie zamknięcie strumienia wyjściowego,response.getOutputStream().close()
aby JAX-RS nie mógł zresetować mojego statusu.response.flushBuffer()
, aby uniknąć przesłaniania kodu odpowiedzi przez ramę. Niezbyt czysty.404 Not Found
, może być łatwiej po prostu użyćthrow new NotFoundException()
.Jeśli chcesz utrzymać warstwę zasobów w czystości od
Response
obiektów, zalecamy użycie@NameBinding
i powiązanie z implementacjamiContainerResponseFilter
.Oto treść adnotacji:
Oto mięso filtra:
A następnie implementacja zasobu staje się po prostu:
źródło
StatusFilter
z@Status
: albo trzeba dostarczyć domyślne adnotacji wvalue
polu, albo zadeklarować jedną klasę podczas nanoszenia (np@Status(200)
). To oczywiście nie jest idealne.Jeśli chcesz zmienić kod statusu z powodu wyjątku, w JAX-RS 2.0 możesz zaimplementować ExceptionMapper w ten sposób. To obsługuje ten rodzaj wyjątku dla całej aplikacji.
źródło
Jeśli Twój WS-RS wymaga zgłoszenia błędu, dlaczego nie skorzystać z wyjątku WebApplicationException?
źródło
JAX-RS obsługuje standardowe / niestandardowe kody HTTP. Zobacz ResponseBuilder i ResponseStatus, na przykład:
http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29
Pamiętaj, że informacje JSON dotyczą bardziej danych związanych z zasobem / aplikacją. Kody HTTP odnoszą się bardziej do statusu żądanej operacji CRUD. (przynajmniej tak powinno być w systemach REST)
źródło
Uważam, że bardzo przydatne jest zbudowanie również komunikatu JSON z powtarzającym się kodem:
źródło
Spójrz na przykład tutaj, najlepiej ilustrujący problem i sposób jego rozwiązania w najnowszej (2.3.1) wersji Jersey.
https://jersey.java.net/documentation/latest/representations.html#d0e3586
Zasadniczo polega na zdefiniowaniu niestandardowego wyjątku i zachowaniu typu zwracanego jako bytu. Gdy wystąpi błąd, zgłaszany jest wyjątek, w przeciwnym razie zwracane jest POJO.
źródło
Response
w niej klasę wyjątków . PoszukajCustomNotFoundException
klasy i może skopiuj ją do swojego postu.Nie używam JAX-RS, ale mam podobny scenariusz, w którym używam:
źródło
Zauważ też, że domyślnie Jersey zastąpi treść odpowiedzi w przypadku kodu http 400 lub więcej.
Aby uzyskać określoną jednostkę jako treść odpowiedzi, spróbuj dodać następujący parametr inicjujący do swojego Jersey w pliku konfiguracyjnym web.xml:
źródło
Poniższy kod działał dla mnie. Wstrzyknięcie messageContext za pomocą setera z adnotacjami i ustawienie kodu stanu w mojej metodzie „dodaj”.
źródło
Rozwijając na odpowiedź z Nthalk z Microprofile OpenAPI można wyrównać kod zwrotny z wykorzystaniem dokumentacji @APIResponse adnotacji.
Umożliwia to oznaczenie metody JAX-RS takiej jak
Możesz parsować tę znormalizowaną adnotację za pomocą ContainerResponseFilter
Zastrzeżenie występuje, gdy umieścisz wiele adnotacji w swojej metodzie jak
źródło
Używam jersey 2.0 z czytnikami treści i pisarzami. Miałem typ zwracanej metody jako konkretny byt, który był również używany przy implementacji programu piszącego treść komunikatu, i zwracałem to samo pojęcie, SkuListDTO. @GET @Consumes ({„application / xml”, „application / json”}) @Produces ({„application / xml”, „application / json”}) @Path („/ skuResync”)
wszystko, co zmieniłem, to to, zostawiłem implementację programu piszącego i nadal działało.
źródło