Spring Boot Rest Controller, comment renvoyer différents codes d'état HTTP?

102

J'utilise Spring Boot pour une API REST simple et j'aimerais renvoyer un code d'état HTTP correct si quelque chose échoue.

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
@ResponseBody
@ResponseStatus( HttpStatus.OK )
public RestModel create(@RequestBody String data) {
    // code ommitted..
    // how do i return a correct status code if something fails?
}

Étant nouveau dans Spring et Spring Boot, la question de base est de savoir comment renvoyer différents codes de statut lorsque quelque chose ne va pas ou échoue?

Marco
la source

Réponses:

117

Vous pouvez utiliser plusieurs options. Un très bon moyen est d'utiliser des exceptions et une classe pour la gestion appelée @ControllerAdvice:

@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ResponseStatus(HttpStatus.CONFLICT)  // 409
    @ExceptionHandler(DataIntegrityViolationException.class)
    public void handleConflict() {
        // Nothing to do
    }
}

Vous pouvez également passer HttpServletResponseà la méthode du contrôleur et définir simplement le code de réponse:

public RestModel create(@RequestBody String data, HttpServletResponse response) {
    // response committed...
    response.setStatus(HttpServletResponse.SC_ACCEPTED);
}

Veuillez vous référer à cet excellent article de blog pour plus de détails: Gestion des exceptions dans Spring MVC


REMARQUE

Dans Spring MVC, l'utilisation de l' @ResponseBodyannotation est redondante - elle est déjà incluse dans l' @RestControllerannotation.

Jakub Kubrynski
la source
Juste comme commentaire, j'ai fait un test il y a 15 minutes, et un '@RestController' sans l'annotation '@ResponseBody' sur sa méthode a placé la chaîne retournée non pas à l'intérieur du corps mais en tant que ForwardedURL. Je suis plutôt noob avec le printemps / le printemps, je ne peux donc pas expliquer pourquoi
Anearion
@Anearion Il y a une faute de frappe dans la réponse - nous avons en fait besoin de «@RestControllerAdvice», pas de «@RestController».
yoliho
Ce n'est pas une faute de frappe. Cette partie est liée à la question et aux annotations sur un contrôleur
Jakub Kubrynski
1
Notez que cela ne javax.servlet.http.HttpServletResponsesemble pas avoir tous les StatusCodes org.springframework.http.HttpStatus. Vous pouvez donc utiliser HttpStatus.UNPROCESSABLE_ENTITY.value()pour passer la valeur int dans response.setStatus. Cela fonctionne également parfaitement pour la gestion des erreurs en utilisant @ExceptionHandler.
Igor
43

Pour ce faire, vous pouvez utiliser ResponseEntity comme objet de retour.

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)

public ResponseEntity<?> create(@RequestBody String data) {

if(everything_fine)
    return new ResponseEntity<>(RestModel, HttpStatus.OK);
else
    return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);

}
Ankit Basarkar
la source
3
Pas besoin d'utiliser la valeur null dans les versions ultérieures de Spring: new ResponseEntity <> (HttpStatus.NOT_FOUND)
Kong
4

Essayez ce code:

@RequestMapping(value = "/validate", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<ErrorBean> validateUser(@QueryParam("jsonInput") final String jsonInput) {
    int numberHTTPDesired = 400;
    ErrorBean responseBean = new ErrorBean();
    responseBean.setError("ERROR");
    responseBean.setMensaje("Error in validation!");

    return new ResponseEntity<ErrorBean>(responseBean, HttpStatus.valueOf(numberHTTPDesired));
}
Rodrigo Hernandez
la source
Comme il s'agit d'une question plutôt ancienne, vous devez donc ajouter les informations sur le package et la version auxquelles vous vous référez.
ZF007 le
Pouvez-vous inclure un exemple de mise en œuvre de ErrorBean?
Brent Bradburn
3

Un bon moyen est d'utiliser l'exception ResponseStatusException de Spring

Plutôt que de renvoyer un ResponseEntityou similaire, vous lancez simplement le ResponseStatusExceptiondepuis le contrôleur avec un HttpStatuset une cause, par exemple:

throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cause description here");

ou:

throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Cause description here");

Cela se traduit par une réponse au client contenant l'état HTTP (par exemple 400 Bad request) avec un corps comme:

{
  "timestamp": "2020-07-09T04:43:04.695+0000",
  "status": 400,
  "error": "Bad Request",
  "message": "Cause description here",
  "path": "/test-api/v1/search"
}
Continuité8
la source
2

Si vous souhaitez renvoyer un code de statut personnalisé, vous pouvez utiliser ResponseEntity comme ici:

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
public ResponseEntity<?> create(@RequestBody String data) {
    int customHttpStatusValue = 499;
    Foo foo = bar();
    return ResponseEntity.status(customHttpStatusValue).body(foo);
}

La CustomHttpStatusValue peut être n'importe quel entier à l'intérieur ou à l'extérieur des codes d'état HTTP standard.

Vedant Goenka
la source
J'aime cette approche API fluide.
v.ladynev le
0

Il existe différentes façons de renvoyer le code d'état, 1: la classe RestController doit étendre la classe BaseRest, dans la classe BaseRest, nous pouvons gérer les exceptions et renvoyer les codes d'erreur attendus. par exemple :

@RestController
@RequestMapping
class RestController extends BaseRest{

}

@ControllerAdvice
public class BaseRest {
@ExceptionHandler({Exception.class,...})
    @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorModel genericError(HttpServletRequest request, 
            HttpServletResponse response, Exception exception) {
        
        ErrorModel error = new ErrorModel();
        resource.addError("error code", exception.getLocalizedMessage());
        return error;
    }
Manju D
la source