2014-05-25 10 views
26

Ho il seguente codice:Come restituisco la risposta HTTP 404 JSON/XML in JAX-RS (Jersey) su Tomcat?

@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; 
    } 

Se chiedo per un utente che non esiste, come /users/1234, con "Accept: application/json", questo codice restituisce un HTTP 404 risposta, come ci si aspetterebbe, ma restituisce Content-Type set a text/html e un messaggio corpo di html. L'annotazione @Produces viene ignorata.

Si tratta di un problema di codice o di un problema di configurazione?

risposta

26

tuo @Produces annotazione viene ignorato perché le eccezioni non gestite fanno vengono elaborati dal runtime JAX-RS utilizzando un predefinito (di default) ExceptionMapper Se si desidera personalizzare il messaggio restituito in caso di una deroga specifica è possibile creare il possedere ExceptionMapper per gestirlo. Nel tuo caso avete bisogno di uno per gestire l'eccezione NotFoundException e interrogare l'intestazione "accetta" per il tipo di risposta richiesto:

@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

L'ho provato. Continuo a lanciare NotFoundException, ma ora associo tale eccezione utilizzando ExceptionMapper per impostare il codice di stato e il tipo di supporto. Funziona! Prima di questo ho provato a restituire una risposta equivalente, invece di lanciare NotFoundException, ma ho lo stesso risultato, una risposta 404 text/html. Questo comportamento è dovuto al fatto che se la mia app genera una NotFoundException l'eccezione (implicita) ExceptionMapper arriva e sovrascrive la risposta che ritorna alla risposta HTML? Grazie! – IJR

+1

Dopo aver provato una soluzione diversa, questa è la soluzione migliore e corretta. Non è obbligatorio mappare * NotFoundException *. Basta usare Exception e fare ciò di cui hai bisogno – Valijon

+0

@Provider è molto importante –

0

che 404 viene restituito dal server in quanto si prevede che si passa le cose in forma seguente

/users/{id} 

ma si passa come

/users/user/{id} 

quale risorsa non è esistente a tutti

provare ad accedere a risorse come /users/1234

EDIT:

creare una classe come

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

ora nel caso in cui si vuole risposta per User si può creare come segue

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

e la firma del metodo resto sarebbe come segue

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

mentre in caso di risposta riuscita è possibile impostare cose come

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 richiesto aggiornato, ho commesso un errore durante la digitazione dell'URI. L'URI corretto è users/1234 per ottenere la risposta 404 in html ma non in JSON. Il mio problema non è il codice di risposta, ma il formato di risposta (tipo di contenuto). – IJR

+0

rimuovere MediaType.APPLICATION_XML da produce e provare, assicurarsi anche di dare un messaggio corretto nel caso in cui l'utente non sia presente.di solito creiamo una risposta di riposo che conterrà lo stato e il messaggio per la richiesta dell'utente e restituiremo la stessa risposta quando qualcuno tenta di accedere alla risorsa –

+0

Ho provato a rimuovere MediaType.APPLICATION_XML dall'annotazione @Produces e ottengo lo stesso risultato, una risposta 404 con text/html Content-Type. È come se Tomcat inviasse il messaggio di tipo contenuto e corpo ... – IJR

11

È possibile utilizzare il ritorno di risposta. Esempio di seguito:

@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

Questo ha funzionato per me con 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(); 
} 

anche avevo bisogno di annotare il metodo con @Produces(MediaType.APPLICATION_JSON) come @Tiago indicato.

Problemi correlati