Spring Boot Rest Controller, як повернути різні коди стану HTTP?


102

Я використовую Spring Boot для простого REST API і хотів би повернути правильний код стану HTTP, якщо щось не вдається.

@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?
}

Будучи новим у Spring та Spring Boot, основне питання полягає в тому, як повернути різні коди стану, коли щось гаразд або не вдається?

Відповіді:


117

Є кілька варіантів, якими ви можете скористатися. Цілком вдалим способом є використання винятків та класу для обробки, що називається @ControllerAdvice:

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

Також ви можете перейти HttpServletResponseдо методу контролера і просто встановити код відповіді:

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

Будь ласка, зверніться до цього чудового допису в блозі для отримання детальної інформації: Обробка винятків у Spring MVC


ПРИМІТКА

Навесні MVC з використанням @ResponseBodyанотації зайвий - він уже включений в @RestControllerанотацію.


Так само, як коментар, я зробив тест 15 хвилин тому, і "@RestController" без анотації "@ResponseBody" над його методом розмістив рядок, повернутий не всередині тіла, а як ForwardedURL. Я симпатичний нуб з весною / весняним завантаженням, тому не можу вказати, чому
Анеаріон

@Anearion У відповіді є помилка - нам насправді потрібен '@RestControllerAdvice', а не '@RestController'.
yoliho

Це не друкарська помилка. Ця частина пов’язана з питанням та анотаціями на контролері
Якуб Кубринський

1
Зверніть увагу, що, javax.servlet.http.HttpServletResponseздається, є не всі коди стану, які є org.springframework.http.HttpStatus. Таким чином, ви можете використовувати HttpStatus.UNPROCESSABLE_ENTITY.value()для передачі значення int у response.setStatus. Також це чудово працює для обробки помилок за допомогою @ExceptionHandler.
Ігор

43

Один із способів зробити це - ви можете використовувати ResponseEntity як об'єкт повернення.

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

}

3
Не потрібно використовувати null у пізніших версіях Spring: new ResponseEntity <> (HttpStatus.NOT_FOUND)
Kong,

4

Спробуйте цей код:

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

Оскільки це досить давнє запитання, вам слід додати інформацію про пакет та версію, на яку ви посилаєтесь.
ZF007

Чи можете ви включити приклад реалізації ErrorBean?
Брент Бредберн,

3

Приємним способом є використання ResponseStatusException Spring

Замість того, щоб повернути a ResponseEntityабо подібне, ви просто викидаєте ResponseStatusExceptionз контролера за допомогою HttpStatusand і причини, наприклад:

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

або:

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

Це призводить до відповіді клієнту, що містить статус HTTP (наприклад, 400 Помилковий запит) із таким текстом, як:

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

2

Якщо ви хочете повернути спеціально визначений код стану, ви можете використовувати ResponseEntity, як тут:

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

CustomHttpStatusValue може бути будь-яким цілим числом у межах або поза стандартними кодами стану HTTP.


Мені подобається такий вільний підхід до API.
v.ladynev

0

Існують різні способи повернення коду стану: 1: Клас RestController повинен розширювати клас BaseRest, у класі BaseRest ми можемо обробляти винятки та повертати очікувані коди помилок. наприклад :

@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;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.