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, основной вопрос заключается в том, как мне вернуть разные коды состояния, когда что-то в порядке или не удается?

Марко
источник

Ответы:

118

Вы можете использовать несколько вариантов. Неплохой способ - использовать исключения и класс для обработки, называемый @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


НОТА

В Spring 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 02
Можете ли вы включить пример реализации ErrorBean?
Брент Брэдберн
4

Хороший способ - использовать Spring ResponseStatusException

Вместо того, чтобы возвращать ResponseEntityили аналогичный, вы просто бросаете ResponseStatusExceptionиз контроллера с помощью HttpStatusи, например:

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

или:

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

Это приводит к ответу клиенту, содержащему статус HTTP (например, 400 Bad request) с телом вроде:

{
  "timestamp": "2020-07-09T04:43:04.695+0000",
  "status": 400,
  "error": "Bad Request",
  "message": "Cause description here",
  "path": "/test-api/v1/search"
}
Непрерывность8
источник
Простой, чистый и потребляемый клиентом REST.
Алек
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-подход.
В.Ладынев
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;
    }
Манджу Д.
источник