web-dev-qa-db-fra.com

Réponse d'état HTTP personnalisé avec JAX-RS (Jersey) et @roxowered

Avec mon service Jax-Rs très simple, j'utilise Tomcat avec JDBC Realm pour l'authentification, je travaille donc les annotations JSR 250.

La chose est que je veux retourner un corps de message personnalisé dans la réponse à l'état HTTP. Le code d'état (403) devrait rester identique. Par exemple, mon service ressemble à ce qui suit:

@RolesAllowed({ "ADMIN" })
@Path("/users")
public class UsersService {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public String getUsers() {
        // get users ...
        return ...;
    }
}

Si un utilisateur ayant un rôle différent de "admin" accède au service, je souhaite modifier le message de réponse à quelque chose comme ça (en fonction du type de support [XML/JSON]):

<error id="100">
    <message>Not allowed.</message>
</error>

Pour le moment, Jersey renvoie le corps suivant:

HTTP Status 403 - Forbidden

type Status report
message Forbidden
description Access to the specified resource (Forbidden) has been forbidden.
Apache Tomcat/7.0.12

Comment puis-je modifier le corps du message par défaut? Existe-t-il un moyen de gérer l'exception (peut-être lancée) pour construire ma propre réponse d'état HTTP?

16
Stefan

Le moyen le plus simple de gérer ce genre de chose est de lancer une exception et d'enregistrer une carte d'exception pour convertir dans le type de message que vous souhaitez envoyer dans ce cas. Alors, supposons que vous lanciez un AccessDeniedException, vous auriez alors un gestionnaire comme celui-ci (avec des noms de classe complète dans les lieux de clarté):

@javax.ws.rs.ext.Provider
public class AccessDeniedHandler
        implements javax.ws.rs.ext.ExceptionMapper<AccessDeniedException> {
    public javax.ws.rs.core.Response toResponse(AccessDeniedException exn) {
        // Construct+return the response here...
        return Response.status(403).type("text/plain")
                .entity("get lost, loser!").build();
    }
}

La manière dont vous enregistrez le mapper d'exception varie en fonction du cadre que vous utilisez, mais pour Jersey, vous devez avoir une bonne avec l'utilisation de @Provider. Je vous tiens à comprendre pour vous-même comment vous souhaitez générer le type de documents d'erreur que vous souhaitez, mais je recommande de manipuler des échecs en tant que codes d'erreur HTTP de quelque sorte (c'est plus reposant ...)

20
Donal Fellows

Avec la création d'un ExceptionMapper (exceptions de mappage de WebApplicationException) Il est possible de "attraper" certaines exceptions projetées par l'application:

@Provider
public class MyExceptionMapper implements ExceptionMapper<WebApplicationException> {

    @Override
    public Response toResponse(WebApplicationException weException) {

        // get initial response
        Response response = weException.getResponse();

        // create custom error
        MyError error = ...;

        // return the custom error
        return Response.status(response.getStatus()).entity(error).build();
    }
}

Vous devez également ajouter le package à votre application Web.xml pour enregistrer le fournisseur:

<init-param>
    <param-name>com.Sun.jersey.config.property.packages</param-name>
    <param-value>
        com.myapp.userservice; // semi-colon seperated
        com.myapp.mappedexception
    </param-value>
</init-param>
9
Stefan

Le repos est construit sur http afin que vous ne puissiez pas modifier le comportement par défaut d'une défaillance d'authentification. Avoir une erreur 403 lors de l'accès à une ressource suffit à comprendre clairement ce qui append.

Plus vos ressources sont confidentielles HTTP, plus les autres peuvent le comprendre.

1
yves amsellem