Utilizzo di Spring ResponseEntity per manipolare la risposta HTTP

1. Introduzione

Usando Spring, di solito abbiamo molti modi per raggiungere lo stesso obiettivo, inclusa la messa a punto delle risposte HTTP.

In questo breve tutorial, vedremo come impostare il corpo, lo stato e le intestazioni di una risposta HTTP utilizzando ResponseEntity .

2. ResponseEntity

ResponseEntity rappresenta l'intera risposta HTTP: codice di stato, intestazioni e corpo . Di conseguenza, possiamo usarlo per configurare completamente la risposta HTTP.

Se vogliamo usarlo, dobbiamo restituirlo dall'endpoint; La primavera si occupa del resto.

ResponseEntity è un tipo generico. Di conseguenza, possiamo utilizzare qualsiasi tipo come corpo della risposta:

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

Poiché specifichiamo lo stato della risposta a livello di codice, possiamo restituire codici di stato diversi per scenari diversi:

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

Inoltre, possiamo impostare le intestazioni HTTP:

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

Inoltre, ResponseEntity fornisce due interfacce di builder annidate : HeadersBuilder e la sua sottointerfaccia, BodyBuilder . Pertanto, possiamo accedere alle loro capacità tramite i metodi statici di ResponseEntity .

Il caso più semplice è una risposta con un corpo e un codice di risposta HTTP 200:

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

Per i codici di stato HTTP più popolari otteniamo metodi statici:

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

Inoltre, possiamo utilizzare i metodi BodyBuilder status (HttpStatus status) e BodyBuilder status (int status) per impostare qualsiasi stato HTTP.

Infine, con ResponseEntity BodyBuilder.body (T body) possiamo impostare il corpo della risposta 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)); }

Possiamo anche impostare intestazioni personalizzate:

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

Poiché BodyBuilder.body () restituisce ResponseEntity invece di BodyBuilder, dovrebbe essere l'ultima chiamata.

Nota che con HeaderBuilder non possiamo impostare alcuna proprietà del corpo della risposta.

Mentre tornava ResponseEntity oggetto dal controller, potremmo ottenere un'eccezione o errore durante l'elaborazione della richiesta e vorrebbe tornare informazioni di errore relative all'utente rappresentato come un altro tipo, diciamo E .

Spring 3.2 offre il supporto per un @ExceptionHandler globale con la nuova annotazione @ControllerAdvice , che gestisce questo tipo di scenari. Per dettagli approfonditi, fare riferimento al nostro articolo esistente qui.

Sebbene ResponseEntity sia molto potente, non dovremmo abusarne. In casi semplici, ci sono altre opzioni che soddisfano le nostre esigenze e danno come risultato un codice molto più pulito.

3. Alternative

3.1. @ResponseBody

Nelle classiche applicazioni Spring MVC, gli endpoint di solito restituiscono pagine HTML sottoposte a rendering. A volte dobbiamo solo restituire i dati effettivi; ad esempio, quando usiamo l'endpoint con AJAX.

In questi casi, possiamo contrassegnare il metodo del gestore della richiesta con @ResponseBody e Spring tratta il valore del risultato del metodo come il corpo della risposta HTTP stesso.

Per ulteriori informazioni, questo articolo è un buon punto di partenza.

3.2. @ResponseStatus

Quando un endpoint viene restituito correttamente, Spring fornisce una risposta HTTP 200 (OK). Se l'endpoint genera un'eccezione, Spring cerca un gestore di eccezioni che dica quale stato HTTP utilizzare.

Possiamo contrassegnare questi metodi con @ResponseStatus e, pertanto, Spring restituisce uno stato HTTP personalizzato .

Per ulteriori esempi, consulta il nostro articolo sui codici di stato personalizzati.

3.3. Manipola la risposta direttamente

Spring ci consente inoltre di accedere direttamente all'oggetto javax.servlet.http.HttpServletResponse ; dobbiamo solo dichiararlo come argomento del metodo:

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

Poiché Spring fornisce astrazioni e funzionalità aggiuntive rispetto all'implementazione sottostante, non dovremmo manipolare la risposta in questo modo .

4. Conclusione

In questo articolo, abbiamo discusso diversi modi per manipolare la risposta HTTP in Spring e ne abbiamo esaminato i vantaggi e gli svantaggi.

Come al solito, gli esempi sono disponibili su GitHub.