Estoy escribiendo una aplicación web REST (NetBeans 6.9, JAX-RS, TopLink Essentials) e intento devolver el código de estado JSON y HTTP. Tengo un código listo y funcionando que devuelve JSON cuando se llama al método HTTP GET desde el cliente. Esencialmente:
@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {
// some code to return JSON ...
return myJson;
}
Pero también quiero devolver un código de estado HTTP (500, 200, 204, etc.) junto con los datos JSON.
Traté de usar HttpServletResponse
:
response.sendError("error message", 500);
Pero esto hizo que el navegador pensara que es un 500 "real", por lo que la página web de salida era una página de error HTTP 500 normal.
Quiero devolver un código de estado HTTP para que mi JavaScript del lado del cliente pueda manejar cierta lógica dependiendo de ello (por ejemplo, mostrar el código de error y el mensaje en una página HTML). ¿Es esto posible o no deberían utilizarse los códigos de estado HTTP para tal cosa?
fuente
Respuestas:
Aquí hay un ejemplo:
Echa un vistazo a la clase de respuesta .
Tenga en cuenta que siempre debe especificar un tipo de contenido, especialmente si está pasando varios tipos de contenido, pero si cada mensaje se representará como JSON, puede simplemente anotar el método con
@Produces("application/json")
fuente
return Response.status(Response.Status.Forbidden).entity(myPOJO).build();
Works como si lo hicierareturn myPOJO;
, pero con una configuración adicional del código de estado HTTP.Hay varios casos de uso para configurar códigos de estado HTTP en un servicio web REST, y al menos uno no estaba suficientemente documentado en las respuestas existentes (es decir, cuando está utilizando la serialización JSON / XML auto-mágica utilizando JAXB, y desea devolver un objeto para ser serializado, pero también un código de estado diferente al predeterminado 200).
Permítanme intentar enumerar los diferentes casos de uso y las soluciones para cada uno:
1. Código de error (500, 404, ...)
El caso de uso más común cuando desea devolver un código de estado diferente de
200 OK
cuando ocurre un error.Por ejemplo:
a) Lanzar una excepción
En ese caso, creo que la forma más limpia de manejar el problema es lanzar una excepción. Esta excepción será manejada por un
ExceptionMapper
, que traducirá la excepción en una respuesta con el código de error apropiado.Puede usar el valor predeterminado
ExceptionMapper
que viene preconfigurado con Jersey (y supongo que es lo mismo con otras implementaciones) y arrojar cualquiera de las subclases existentes dejavax.ws.rs.WebApplicationException
. Estos son tipos de excepción predefinidos que se asignan previamente a diferentes códigos de error, por ejemplo:Etc. Puede encontrar la lista aquí: API
Alternativamente, puede definir sus propias excepciones y
ExceptionMapper
clases personalizadas, y agregar estos mapeadores a Jersey por medio de la@Provider
anotación ( fuente de este ejemplo ):Proveedor :
Nota: también puede escribir ExceptionMappers para los tipos de excepción existentes que usa.
b) Use el generador de respuestas
Otra forma de establecer un código de estado es usar un
Response
generador para generar una respuesta con el código deseado.En ese caso, el tipo de retorno de su método debe ser
javax.ws.rs.core.Response
. Esto se describe en varias otras respuestas, como la respuesta aceptada de hisdrewness y se ve así:2. Éxito, pero no 200
Otro caso en el que desea establecer el estado de retorno es cuando la operación fue exitosa, pero desea devolver un código de éxito diferente de 200, junto con el contenido que devuelve en el cuerpo.
Un caso de uso frecuente es cuando crea una nueva entidad (
POST
solicitud) y desea devolver información sobre esta nueva entidad o tal vez la entidad misma, junto con un201 Created
código de estado.Un enfoque es utilizar el objeto de respuesta tal como se describió anteriormente y establecer el cuerpo de la solicitud usted mismo. Sin embargo, al hacer esto, pierde la capacidad de utilizar la serialización automática a XML o JSON proporcionada por JAXB.
Este es el método original que devuelve un objeto de entidad que JAXB serializará a JSON:
Esto devolverá una representación JSON del usuario recién creado, pero el estado de devolución será 200, no 201.
Ahora el problema es que si quiero usar el
Response
generador para configurar el código de retorno, tengo que devolver unResponse
objeto en mi método. ¿Cómo devuelvo elUser
objeto para que se serialice?a) Establezca el código en la respuesta del servlet
Un enfoque para resolver esto es obtener un objeto de solicitud de servlet y establecer el código de respuesta manualmente nosotros mismos, como se demuestra en la respuesta de Garett Wilson:
El método aún devuelve un objeto de entidad y el código de estado será 201.
Tenga en cuenta que para que funcione, tuve que vaciar la respuesta. Este es un resurgimiento desagradable del código API de Servlet de bajo nivel en nuestro agradable recurso JAX_RS, y mucho peor, hace que los encabezados no se puedan modificar después de esto porque ya se enviaron por cable.
b) Use el objeto de respuesta con la entidad
La mejor solución, en ese caso, es usar el objeto de Respuesta y configurar la entidad para que se serialice en este objeto de respuesta. Sería bueno hacer que el objeto Respuesta sea genérico para indicar el tipo de entidad de carga útil en ese caso, pero no es el caso actual.
En ese caso, utilizamos el método creado de la clase de generador de Respuesta para establecer el código de estado en 201. Pasamos el objeto de entidad (usuario) a la respuesta a través del método de entidad ().
El resultado es que el código HTTP es 401 como queríamos, y el cuerpo de la respuesta es exactamente el mismo JSON que teníamos antes cuando acabamos de devolver el objeto Usuario. También agrega un encabezado de ubicación.
La clase Response tiene varios métodos de creación para diferentes estados (stati?) Como:
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
NB: el objeto hateoas es una clase auxiliar que desarrollé para ayudar a generar recursos URI. Tendrá que crear su propio mecanismo aquí;)
Eso es todo.
Espero que esta larga respuesta ayude a alguien :)
fuente
flush
es de hecho sucio.La respuesta de hisdrewness funcionará, pero modifica todo el enfoque para permitir que un proveedor como Jackson + JAXB convierta automáticamente su objeto devuelto a algún formato de salida como JSON. Inspirado por una publicación Apache CXF (que usa una clase específica de CXF), he encontrado una forma de configurar el código de respuesta que debería funcionar en cualquier implementación JAX-RS: inyectar un contexto HttpServletResponse y configurar manualmente el código de respuesta. Por ejemplo, aquí se explica cómo configurar el código de respuesta
CREATED
cuando sea apropiado.Mejora: ¡ Después de encontrar otra respuesta relacionada , aprendí que se puede inyectar la
HttpServletResponse
variable como miembro, incluso para la clase de servicio singleton (al menos en RESTEasy) !! Este es un enfoque mucho mejor que contaminar la API con detalles de implementación. Se vería así:fuente
@Produces
, y no especifique el tipo de medio en la finalResponse.ok
, y obtendrá su objeto de retorno correctamente serializado en JAXB en el tipo de medio apropiado para que coincida con la solicitud. (Acabo de probar esto con un único método que podría devolver XML o JSON: el método en sí no necesita mencionar ninguno, excepto en la@Produces
anotación.)MessageBodyWriter
yProvider
permite la negociación de contenido implícito, aunque parece que su ejemplo le falta algún código. Aquí hay otra respuesta que proporcioné que ilustra esto: stackoverflow.com/questions/5161466/…response.setStatus()
. La única forma de enviar, por ejemplo, una respuesta 404 No encontrado es establecer el código de estado de respuestaresponse.setStatus(404)
y luego cerrar la secuencia de salidaresponse.getOutputStream().close()
para que JAX-RS no pueda restablecer mi estado.response.flushBuffer()
para evitar que el marco anulara mi código de respuesta. No muy limpio404 Not Found
, puede ser más fácil de usarthrow new NotFoundException()
.Si desea mantener su capa de recursos limpia de
Response
objetos, le recomiendo que use@NameBinding
y enlace a implementaciones deContainerResponseFilter
.Aquí está la carne de la anotación:
Aquí está la carne del filtro:
Y luego la implementación en su recurso simplemente se convierte en:
fuente
StatusFilter
con@Status
: debe proporcionar un valor predeterminado para elvalue
campo de la anotación , o declarar uno al anotar la clase (por ejemplo:)@Status(200)
. Esto obviamente no es ideal.En caso de que desee cambiar el código de estado debido a una excepción, con JAX-RS 2.0 puede implementar un ExceptionMapper como este. Esto maneja este tipo de excepción para toda la aplicación.
fuente
Si su WS-RS necesita generar un error, ¿por qué no usar la excepción WebApplicationException?
fuente
JAX-RS tiene soporte para códigos HTTP estándar / personalizados. Consulte ResponseBuilder y ResponseStatus, por ejemplo:
http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29
Tenga en cuenta que la información JSON es más sobre los datos asociados con el recurso / aplicación. Los códigos HTTP tratan más sobre el estado de la operación CRUD que se solicita. (al menos así es como se supone que debe ser en los sistemas REST-ful)
fuente
Me pareció muy útil construir también un mensaje json con código repetido, como este:
fuente
Mire el ejemplo aquí, ilustra mejor el problema y cómo se resuelve en la última versión (2.3.1) de Jersey.
https://jersey.java.net/documentation/latest/representations.html#d0e3586
Básicamente implica definir una excepción personalizada y mantener el tipo de retorno como la entidad. Cuando hay un error, se lanza la excepción, de lo contrario, devuelve el POJO.
fuente
Response
en ella. Simplemente busque laCustomNotFoundException
clase y tal vez cópiela en su publicación.No estoy usando JAX-RS, pero tengo un escenario similar donde uso:
fuente
Además, tenga en cuenta que, de manera predeterminada, Jersey anulará el cuerpo de respuesta en caso de un código http 400 o más.
Para obtener su entidad especificada como el cuerpo de respuesta, intente agregar el siguiente parámetro init a su Jersey en su archivo de configuración web.xml:
fuente
El siguiente código funcionó para mí. Inyectando el mensajeContexto a través de un anotador establecido y configurando el código de estado en mi método "agregar".
fuente
Ampliando la respuesta de Nthalk con Microprofile OpenAPI , puede alinear el código de retorno con su documentación utilizando la anotación @APIResponse .
Esto permite etiquetar un método JAX-RS como
Puede analizar esta anotación estandarizada con un ContainerResponseFilter
Una advertencia ocurre cuando pones múltiples anotaciones en tu método como
fuente
Estoy usando jersey 2.0 con lectores y escritores de mensajes. Tenía mi tipo de retorno de método como una entidad específica que también se usó en la implementación del escritor del cuerpo del mensaje y estaba devolviendo el mismo pojo, un SkuListDTO. @GET @Consumes ({"application / xml", "application / json"}) @Produces ({"application / xml", "application / json"}) @Path ("/ skuResync")
todo lo que cambié fue esto, dejé solo la implementación del escritor y aún funcionó.
fuente