2014-05-25 5 views
26

Ich habe den folgenden Code:Wie gebe ich HTTP 404 JSON/XML Antwort in JAX-RS (Jersey) auf Tomcat zurück?

@Path("https://stackoverflow.com/users/{id}") 
public class UserResource { 

    @Autowired 
    private UserDao userDao; 

    @GET 
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) 
    public User getUser(@PathParam("id") int id) { 
     User user = userDao.getUserById(id); 
     if (user == null) { 
      throw new NotFoundException(); 
     } 
     return user; 
    } 

Wenn ich für einen Benutzer anfordern, die nicht, wie /users/1234, mit „Accept: application/json“ nicht existiert, dieser Code gibt eine HTTP 404 Antwort wie man erwarten würde, gibt aber Content-Type Sets zu text/html und eine Body-Nachricht von HTML. Anmerkung @Produces wird ignoriert.

Ist es ein Problem des Codes oder ein Problem der Konfiguration?

Antwort

26

Ihre @Produces Anmerkung ignoriert wird, weil nicht abgefangene Ausnahmen von der JAX-RS-Laufzeit einen vordefinierten (default) ExceptionMapper Wenn Sie anpassen möchten die zurückgegebene Meldung bei einer bestimmten Ausnahme verarbeitet verwenden, können Sie erstellen Ihre eigene ExceptionMapper, um damit umzugehen. In Ihrem Fall müssen Sie eine der NotFoundException Ausnahme und abfragen, um die „accept“ Header für die gewünschte Art der Antwort zu handhaben:

@Provider 
public class NotFoundExceptionHandler implements ExceptionMapper<NotFoundException>{ 

    @Context 
    private HttpHeaders headers; 

    public Response toResponse(NotFoundException ex){ 
     return Response.status(404).entity(yourMessage).type(getAcceptType()).build(); 
    } 

    private String getAcceptType(){ 
     List<MediaType> accepts = headers.getAcceptableMediaTypes(); 
     if (accepts!=null && accepts.size() > 0) { 
      //choose one 
     }else { 
      //return a default one like Application/json 
     } 
    } 
} 
+0

Ich habe es getestet. Ich fange weiterhin mit NotFoundException ab, mappe diese Ausnahme nun mithilfe von ExceptionMapper, um Statuscode und Medientyp festzulegen. Es klappt! Vorher habe ich versucht, eine gleichwertige Antwort anstelle NotFoundException zurückgeben, aber ich habe das gleiche Ergebnis, eine Text/HTML-404-Antwort. Liegt dieses Verhalten daran, dass, wenn meine App eine NotFoundException auslöst, der standardmäßige (implizite) ExceptionMapper eingeht und die Antwort außer Kraft setzt, die ich zur HTML-Antwort zurückgebe? Danke! – IJR

+1

Nach dem Ausprobieren einer anderen Lösung ist dies die beste und korrekte Lösung. Es ist nicht zwingend erforderlich, * NotFoundException * zuzuordnen. Verwenden Sie einfach Exception und tun Sie, was Sie brauchen – Valijon

+0

@Provider ist sehr wichtig –

0

dass 404 wird von Ihrem Server zurückgegeben, wie es erwartet wird, dass Sie die Dinge in folgenden Form

/users/{id} 

passieren werden, aber sie sind vorbei als

/users/user/{id} 

welche Ressource überhaupt nicht vorhanden ist

try zugreifenden Ressource als /users/1234

EDIT:

erstellen eine Klasse wie

class RestResponse<T>{ 
private String status; 
private String message; 
private List<T> objectList; 
//gettrs and setters 
} 

jetzt im Fall, dass Sie Antwort wollen für User können Sie es schaffen, wie folgend

RestResponse<User> resp = new RestResponse<User>(); 
resp.setStatus("400"); 
resp.setMessage("User does not exist"); 

und Unterschrift des Rest-Methode wie folgt

wäre
public RestResponse<User> getUser(@PathParam("id") int id) 

während im Falle einer erfolgreichen Antwort können Sie einstellen Dinge wie

RestResponse<User> resp = new RestResponse<User>(); 
List<User> userList = new ArrayList<User>(); 
userList.add(user);//the user object you want to return 
resp.setStatus("200"); 
resp.setMessage("User exist"); 
resp.setObjectList(userList); 
+0

URI angefordert aktualisiert, ich habe einen Fehler bei der Eingabe von URI gemacht. Der richtige URI ist Benutzer/1234, um eine 404-Antwort in HTML, aber nicht in JSON zu erhalten. Mein Problem ist nicht der Antwortcode, sondern das Antwortformat (Inhaltstyp). – IJR

+0

entfernen MediaType.APPLICATION_XML von produziert und versuchen, auch sicherstellen, dass Sie richtige Nachricht geben, falls Benutzer nicht existiert.Normalerweise erstellen wir eine Restreaktion, die den Status und die Nachricht für die Benutzeranforderung enthält, und wir geben dieselbe Antwort zurück, wenn jemand versucht, auf die Ressource –

+0

zuzugreifen. Ich habe versucht, MediaType.APPLICATION_XML aus Annotation @Produces zu entfernen und erhalte das gleiche Ergebnis, eine 404 Response mit text/html Inhaltstyp. Es ist wie Tomcat ist Content-Typ und Körper Nachricht überschrieben ... – IJR

11

Sie die Antwort verwenden zurückkehren können. Beispiel unten:

@GET 
@Path("{id}") 
@Produces(MediaType.APPLICATION_JSON) 
public Response get(@PathParam("id") Long id) { 
    ExampleEntity exampleEntity = getExampleEntityById(id); 

    if (exampleEntity != null) { 
     return Response.ok(exampleEntity).build(); 
    } 

    return Response.status(Status.NOT_FOUND).build(); 
} 
-1

Dieser arbeitete für mich mit JAX-RS:

jsonText = "{\n" + " \"account\": {\n" + "  \"billing_account\": \"" + ipResponse.getResult().getParentGUID() + "\",\n" + "}" + ",\n" + "}"; 
parser = new JSONParser(); 

//build our JSON response object 
try { 
    jSONObject = (JSONObject) parser.parse(jsonText); 
    return Response.status(200).entity(jSONObject.toJSONString()).build(); 
} catch (ParseException e) { 
    e.printStackTrace(); 
    jsonEText = "{\n" + " \"account\": {\n" + "  \"billing_account\": \"" + e.getMessage() + "\",\n" + "}" + ",\n" + "}"; 
    jSONObject = (JSONObject) parser.parse(jsonEText); 
    return Response.status(404).entity(jSONObject.toJSONString()).build(); 
} 

ich brauchte auch die Methode mit @Produces(MediaType.APPLICATION_JSON) zu annotieren als @Tiago angegeben.

Verwandte Themen