Uso de Spring ResponseEntity para manipular la respuesta HTTP

1. Introducción

Al usar Spring, generalmente tenemos muchas formas de lograr el mismo objetivo, incluido el ajuste fino de las respuestas HTTP.

En este breve tutorial, veremos cómo configurar el cuerpo, el estado y los encabezados de una respuesta HTTP usando ResponseEntity .

2. ResponseEntity

ResponseEntity representa la respuesta HTTP completa: código de estado, encabezados y cuerpo . Como resultado, podemos usarlo para configurar completamente la respuesta HTTP.

Si queremos usarlo, tenemos que devolverlo desde el punto final; La primavera se encarga del resto.

ResponseEntity es un tipo genérico. En consecuencia, podemos usar cualquier tipo como cuerpo de respuesta:

@GetMapping("/hello") ResponseEntity hello() { return new ResponseEntity("Hello World!", HttpStatus.OK); }

Dado que especificamos el estado de la respuesta mediante programación, podemos regresar con diferentes códigos de estado para diferentes escenarios:

@GetMapping("/age") ResponseEntity age( @RequestParam("yearOfBirth") int yearOfBirth) { if (isInFuture(yearOfBirth)) { return new ResponseEntity( "Year of birth cannot be in the future", HttpStatus.BAD_REQUEST); } return new ResponseEntity( "Your age is " + calculateAge(yearOfBirth), HttpStatus.OK); }

Además, podemos establecer encabezados HTTP:

@GetMapping("/customHeader") ResponseEntity customHeader() { HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "foo"); return new ResponseEntity( "Custom header set", headers, HttpStatus.OK); }

Además, ResponseEntity proporciona dos interfaces de constructor anidadas : HeadersBuilder y su subinterfaz, BodyBuilder . Por tanto, podemos acceder a sus capacidades a través de los métodos estáticos de ResponseEntity .

El caso más simple es una respuesta con un cuerpo y un código de respuesta HTTP 200:

@GetMapping("/hello") ResponseEntity hello() { return ResponseEntity.ok("Hello World!"); }

Para los códigos de estado HTTP más populares, obtenemos métodos estáticos:

BodyBuilder accepted(); BodyBuilder badRequest(); BodyBuilder created(java.net.URI location); HeadersBuilder noContent(); HeadersBuilder notFound(); BodyBuilder ok();

Además, podemos usar los métodos BodyBuilder status (estado HttpStatus) y BodyBuilder status (estado int) para establecer cualquier estado HTTP.

Finalmente, con ResponseEntity BodyBuilder.body (T body) podemos establecer el cuerpo de respuesta HTTP:

@GetMapping("/age") ResponseEntity age(@RequestParam("yearOfBirth") int yearOfBirth) { if (isInFuture(yearOfBirth)) { return ResponseEntity.badRequest() .body("Year of birth cannot be in the future"); } return ResponseEntity.status(HttpStatus.OK) .body("Your age is " + calculateAge(yearOfBirth)); }

También podemos configurar encabezados personalizados:

@GetMapping("/customHeader") ResponseEntity customHeader() { return ResponseEntity.ok() .header("Custom-Header", "foo") .body("Custom header set"); }

Dado que BodyBuilder.body () devuelve ResponseEntity en lugar de BodyBuilder, debería ser la última llamada.

Tenga en cuenta que con HeaderBuilder no podemos establecer ninguna propiedad del cuerpo de la respuesta.

Al regresar ResponseEntity objeto desde el controlador, podríamos obtener una excepción o un error al procesar la solicitud y le gustaría devolver información de error relacionado con el usuario representado como algún otro tipo, digamos E .

Spring 3.2 brinda soporte para un @ExceptionHandler global con la nueva anotación @ControllerAdvice , que maneja este tipo de escenarios. Para obtener detalles en profundidad, consulte nuestro artículo existente aquí.

Si bien ResponseEntity es muy poderoso, no debemos abusar de él. En casos simples, existen otras opciones que satisfacen nuestras necesidades y dan como resultado un código mucho más limpio.

3. Alternativas

3.1. @ResponseCuerpo

En las aplicaciones clásicas de Spring MVC, los puntos finales generalmente devuelven páginas HTML renderizadas. A veces, solo necesitamos devolver los datos reales; por ejemplo, cuando usamos el punto final con AJAX.

En tales casos, podemos marcar el método del controlador de solicitudes con @ResponseBody , y Spring trata el valor de resultado del método como el propio cuerpo de respuesta HTTP .

Para obtener más información, este artículo es un buen lugar para comenzar.

3.2. @ResponseStatus

Cuando un extremo regresa con éxito, Spring proporciona una respuesta HTTP 200 (OK). Si el punto final arroja una excepción, Spring busca un controlador de excepciones que le indique qué estado HTTP usar.

Podemos marcar estos métodos con @ResponseStatus y, por lo tanto, Spring regresa con un estado HTTP personalizado .

Para obtener más ejemplos, visite nuestro artículo sobre códigos de estado personalizados.

3.3. Manipular la respuesta directamente

Spring también nos permite acceder directamente al objeto javax.servlet.http.HttpServletResponse ; solo tenemos que declararlo como argumento de método:

@GetMapping("/manual") void manual(HttpServletResponse response) throws IOException { response.setHeader("Custom-Header", "foo"); response.setStatus(200); response.getWriter().println("Hello World!"); }

Dado que Spring proporciona abstracciones y capacidades adicionales por encima de la implementación subyacente, no deberíamos manipular la respuesta de esta manera .

4. Conclusión

En este artículo, discutimos varias formas de manipular la respuesta HTTP en Spring y examinamos sus beneficios e inconvenientes.

Como de costumbre, los ejemplos están disponibles en GitHub.