Ich schreibe eine REST-Web-App (NetBeans 6.9, JAX-RS, TopLink Essentials) und versuche, JSON- und HTTP-Statuscode zurückzugeben. Ich habe Code bereit und funktioniert, der JSON zurückgibt, wenn die HTTP-GET-Methode vom Client aufgerufen wird. Im Wesentlichen:
@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {
// some code to return JSON ...
return myJson;
}
Ich möchte aber auch einen HTTP-Statuscode (500, 200, 204 usw.) zusammen mit den JSON-Daten zurückgeben.
Ich habe versucht zu verwenden HttpServletResponse
:
response.sendError("error message", 500);
Dies ließ den Browser jedoch denken, dass es sich um eine "echte" 500 handelt, sodass die Ausgabe-Webseite eine reguläre HTTP 500-Fehlerseite war.
Ich möchte einen HTTP-Statuscode zurückgeben, damit mein clientseitiges JavaScript abhängig davon eine gewisse Logik verarbeiten kann (z. B. um den Fehlercode und die Meldung auf einer HTML-Seite anzuzeigen). Ist dies möglich oder sollten für solche Dinge keine HTTP-Statuscodes verwendet werden?
Antworten:
Hier ist ein Beispiel:
Schauen Sie sich die Response- Klasse an.
Beachten Sie, dass Sie immer einen Inhaltstyp angeben sollten, insbesondere wenn Sie mehrere Inhaltstypen übergeben. Wenn jedoch jede Nachricht als JSON dargestellt wird, können Sie die Methode einfach mit Anmerkungen versehen
@Produces("application/json")
quelle
return Response.status(Response.Status.Forbidden).entity(myPOJO).build();
als ob Sie es tun würdenreturn myPOJO;
, jedoch mit zusätzlicher Einstellung des HTTP-Statuscodes.Es gibt mehrere Anwendungsfälle zum Festlegen von HTTP-Statuscodes in einem REST-Webdienst, und mindestens einer wurde in den vorhandenen Antworten nicht ausreichend dokumentiert (z. B. wenn Sie die automatische magische JSON / XML-Serialisierung mit JAXB verwenden und einen zurückgeben möchten zu serialisierendes Objekt, aber auch ein anderer Statuscode als der Standard 200).
Lassen Sie mich versuchen, die verschiedenen Anwendungsfälle und Lösungen für jeden einzelnen aufzuzählen:
1. Fehlercode (500, 404, ...)
Der häufigste Anwendungsfall, wenn Sie einen anderen Statuscode als
200 OK
beim Auftreten eines Fehlers zurückgeben möchten .Beispielsweise:
a) Wirf eine Ausnahme aus
In diesem Fall denke ich, dass der sauberste Weg, um das Problem zu lösen, darin besteht, eine Ausnahme auszulösen. Diese Ausnahme wird von einem behandelt
ExceptionMapper
, der die Ausnahme in eine Antwort mit dem entsprechenden Fehlercode übersetzt.Sie können die
ExceptionMapper
mit Jersey vorkonfigurierte Standardeinstellung verwenden (und ich denke, dass dies auch bei anderen Implementierungen der Fall ist) und eine der vorhandenen Unterklassen von werfenjavax.ws.rs.WebApplicationException
. Hierbei handelt es sich um vordefinierte Ausnahmetypen, die verschiedenen Fehlercodes vorab zugeordnet sind, z. B.:Die Liste finden Sie hier: API
Alternativ können Sie Ihre eigenen benutzerdefinierten Ausnahmen und
ExceptionMapper
Klassen definieren und diese Zuordnungen mithilfe der@Provider
Anmerkung ( Quelle dieses Beispiels ) zu Jersey hinzufügen :Anbieter :
Hinweis: Sie können auch ExceptionMappers für vorhandene Ausnahmetypen schreiben, die Sie verwenden.
b) Verwenden Sie den Response Builder
Eine andere Möglichkeit, einen Statuscode festzulegen, besteht darin, einen
Response
Builder zu verwenden, um eine Antwort mit dem beabsichtigten Code zu erstellen.In diesem Fall muss der Rückgabetyp Ihrer Methode sein
javax.ws.rs.core.Response
. Dies wird in verschiedenen anderen Antworten beschrieben, beispielsweise in der von hisdrewness akzeptierten Antwort, und sieht folgendermaßen aus:2. Erfolg, aber nicht 200
Ein anderer Fall, in dem Sie den Rückgabestatus festlegen möchten, ist, wenn der Vorgang erfolgreich war, Sie jedoch einen anderen Erfolgscode als 200 zusammen mit dem Inhalt zurückgeben möchten, den Sie im Hauptteil zurückgeben.
Ein häufiger Anwendungsfall ist, wenn Sie eine neue Entität (
POST
Anforderung) erstellen und Informationen zu dieser neuen Entität oder möglicherweise zur Entität selbst zusammen mit einem201 Created
Statuscode zurückgeben möchten .Ein Ansatz besteht darin, das Antwortobjekt wie oben beschrieben zu verwenden und den Hauptteil der Anforderung selbst festzulegen. Auf diese Weise verlieren Sie jedoch die Möglichkeit, die von JAXB bereitgestellte automatische Serialisierung in XML oder JSON zu verwenden.
Dies ist die ursprüngliche Methode, die ein Entitätsobjekt zurückgibt, das von JAXB an JSON serialisiert wird:
Dadurch wird eine JSON-Darstellung des neu erstellten Benutzers zurückgegeben, der Rückgabestatus lautet jedoch 200 und nicht 201.
Das Problem ist nun, dass ich
Response
einResponse
Objekt in meiner Methode zurückgeben muss, wenn ich den Builder zum Festlegen des Rückkehrcodes verwenden möchte . Wie kann ich dasUser
zu serialisierende Objekt trotzdem zurückgeben ?a) Stellen Sie den Code in der Servlet-Antwort ein
Ein Ansatz, um dies zu lösen, besteht darin, ein Servlet-Anforderungsobjekt zu erhalten und den Antwortcode manuell selbst festzulegen, wie in Garett Wilsons Antwort gezeigt:
Die Methode gibt weiterhin ein Entitätsobjekt zurück und der Statuscode lautet 201.
Beachten Sie, dass ich die Antwort leeren musste, damit es funktioniert. Dies ist eine unangenehme Wiederbelebung des Servlet-API-Codes auf niedriger Ebene in unserer netten JAX_RS-Ressource. Schlimmer noch, die Header können danach nicht mehr geändert werden, da sie bereits über die Leitung gesendet wurden.
b) Verwenden Sie das Antwortobjekt mit der Entität
In diesem Fall besteht die beste Lösung darin, das Antwortobjekt zu verwenden und die zu serialisierende Entität für dieses Antwortobjekt festzulegen. Es wäre schön, das Response-Objekt generisch zu machen, um den Typ der Nutzdatenentität in diesem Fall anzugeben, dies ist jedoch derzeit nicht der Fall.
In diesem Fall verwenden wir die erstellte Methode der Response Builder-Klasse, um den Statuscode auf 201 zu setzen. Wir übergeben das Entitätsobjekt (Benutzer) über die entity () -Methode an die Antwort.
Das Ergebnis ist, dass der HTTP-Code wie gewünscht 401 lautet und der Hauptteil der Antwort genau derselbe JSON ist, den wir zuvor hatten, als wir gerade das User-Objekt zurückgegeben haben. Außerdem wird ein Standortheader hinzugefügt.
Die Response-Klasse verfügt über eine Reihe von Builder-Methoden für verschiedene Status (stati?), Wie z.
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
NB: Das Hateoas-Objekt ist eine Hilfsklasse, die ich entwickelt habe, um Ressourcen-URIs zu generieren. Sie müssen hier Ihren eigenen Mechanismus entwickeln;)
Das ist alles.
Ich hoffe diese lange Antwort hilft jemandem :)
quelle
flush
ist ja dreckig.Die Antwort von hisdrewness wird funktionieren, ändert jedoch den gesamten Ansatz dahingehend, dass ein Anbieter wie Jackson + JAXB Ihr zurückgegebenes Objekt automatisch in ein Ausgabeformat wie JSON konvertiert. Inspiriert von einem Apache CXF- Beitrag (der eine CXF-spezifische Klasse verwendet) habe ich eine Möglichkeit gefunden, den Antwortcode festzulegen, der in jeder JAX-RS-Implementierung funktionieren soll: Einfügen eines HttpServletResponse-Kontexts und manuelles Festlegen des Antwortcodes. Hier erfahren Sie beispielsweise, wie Sie den Antwortcode
CREATED
gegebenenfalls einstellen .Verbesserung: Nachdem ich eine andere verwandte Antwort gefunden hatte , erfuhr ich, dass man die
HttpServletResponse
Variable als Mitglied auch für Singleton-Serviceklassen (zumindest in RESTEasy) einfügen kann !! Dies ist ein viel besserer Ansatz, als die API mit Implementierungsdetails zu verschmutzen. Es würde so aussehen:quelle
@Produces
und geben Sie den Medientyp im Finale nicht anResponse.ok
, und Sie erhalten Ihr Rückgabeobjekt korrekt JAXB-serialisiert in den entsprechenden Medientyp, um der Anforderung zu entsprechen. (Ich habe dies nur mit einer einzigen Methode versucht, die entweder XML oder JSON zurückgeben kann: Die Methode selbst muss auch nicht erwähnt werden, außer in der@Produces
Anmerkung.)MessageBodyWriter
und zu verwenden,Provider
ermöglicht implizite Inhaltsverhandlungen, obwohl Ihrem Beispiel anscheinend Code fehlt. Hier ist eine andere Antwort, die ich gegeben habe, die dies veranschaulicht: stackoverflow.com/questions/5161466/…response.setStatus()
. Die einzige Möglichkeit, beispielsweise eine 404 Not Found- Antwort zu senden, besteht darin, den Antwortstatuscode festzulegenresponse.setStatus(404)
und dann den Ausgabestream zu schließenresponse.getOutputStream().close()
damit JAX-RS meinen Status nicht zurücksetzen kann.response.flushBuffer()
um zu vermeiden, dass das Framework meinen Antwortcode überschreibt. Nicht sehr sauber.404 Not Found
, ist es möglicherweise einfacher, nur zu verwendenthrow new NotFoundException()
.Wenn Sie Ihre Ressourcenschicht frei von
Response
Objekten halten möchten , empfehle ich die Verwendung@NameBinding
und Bindung an Implementierungen vonContainerResponseFilter
.Hier ist das Fleisch der Anmerkung:
Hier ist das Fleisch des Filters:
Und dann wird die Implementierung auf Ihrer Ressource einfach:
quelle
StatusFilter
mit@Status
: Sie müssen entweder einen Standard für dasvalue
Feld der Annotation angeben oder einen deklarieren, wenn Sie die Klasse annotieren ( z. B. :)@Status(200)
. Dies ist offensichtlich nicht ideal.Wenn Sie den Statuscode aufgrund einer Ausnahme ändern möchten, können Sie mit JAX-RS 2.0 einen solchen ExceptionMapper implementieren. Dies behandelt diese Art von Ausnahme für die gesamte App.
quelle
Wenn Ihr WS-RS einen Fehler auslösen muss, verwenden Sie einfach die WebApplicationException.
quelle
JAX-RS unterstützt Standard- / benutzerdefinierte HTTP-Codes. Siehe ResponseBuilder und ResponseStatus, zum Beispiel:
http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29
Beachten Sie, dass sich JSON-Informationen eher auf die mit der Ressource / Anwendung verknüpften Daten beziehen. In den HTTP-Codes wird mehr über den Status der angeforderten CRUD-Operation berichtet. (Zumindest soll es so in REST-fähigen Systemen sein)
quelle
Ich fand es sehr nützlich, auch eine JSON-Nachricht mit wiederholtem Code zu erstellen, wie folgt:
quelle
Schauen Sie sich das Beispiel hier an, es veranschaulicht das Problem am besten und wie es in der neuesten (2.3.1) Version von Jersey gelöst wird.
https://jersey.java.net/documentation/latest/representations.html#d0e3586
Grundsätzlich müssen Sie eine benutzerdefinierte Ausnahme definieren und den Rückgabetyp als Entität beibehalten. Wenn ein Fehler auftritt, wird die Ausnahme ausgelöst, andernfalls geben Sie das POJO zurück.
quelle
Response
darin erstellen .CustomNotFoundException
Suchen Sie einfach nach der Klasse und kopieren Sie sie möglicherweise in Ihren Beitrag.Ich verwende JAX-RS nicht, aber ich habe ein ähnliches Szenario, in dem ich Folgendes verwende:
quelle
Beachten Sie außerdem, dass Jersey bei einem HTTP-Code 400 oder höher standardmäßig den Antworttext überschreibt.
Versuchen Sie, Ihrem Jersey in Ihrer Konfigurationsdatei web.xml den folgenden init-Parameter hinzuzufügen, um Ihre angegebene Entität als Antworttext zu erhalten:
quelle
Der folgende Code hat bei mir funktioniert. Injizieren des messageContext über einen mit Anmerkungen versehenen Setter und Festlegen des Statuscodes in meiner "add" -Methode.
quelle
Wenn Sie die Antwort von Nthalk mit Microprofile OpenAPI erweitern , können Sie den Rückkehrcode mithilfe von @APIResponse an Ihrer Dokumentation ausrichten Annotation .
Dies ermöglicht das Markieren einer JAX-RS-Methode wie
Sie können diese standardisierte Annotation mit einem ContainerResponseFilter analysieren
Eine Einschränkung tritt auf, wenn Sie Ihrer Methode wie mehrere Anmerkungen hinzufügen
quelle
Ich verwende Jersey 2.0 mit Lesern und Schreibern von Nachrichtenkörpern. Ich hatte meinen Methodenrückgabetyp als eine bestimmte Entität, die auch bei der Implementierung des Nachrichtentextschreibers verwendet wurde, und ich gab das gleiche Pojo zurück, ein SkuListDTO. @GET @Consumes ({"application / xml", "application / json"}) @Produces ({"application / xml", "application / json"}) @Path ("/ skuResync")
Alles, was ich geändert habe, war Folgendes: Ich habe die Writer-Implementierung in Ruhe gelassen und es hat immer noch funktioniert.
quelle