1. Обзор
В этом кратком руководстве мы обсудим новый класс ResponseStatusException
, представленный в Spring 5. Этот класс поддерживает применение кодов состояния HTTP к ответам HTTP.
Приложение RESTful может сообщать об успешном или неудачном выполнении HTTP-запроса, возвращая правильный код состояния в ответе клиенту . Проще говоря, соответствующий код состояния может помочь клиенту определить проблемы, которые могли возникнуть во время обработки запроса приложением.
2. Статус ответа
Прежде чем мы углубимся в ResponseStatusException,
давайте быстро взглянем на аннотацию @ResponseStatus
. Эта аннотация была введена в Spring 3 для применения кода состояния HTTP к ответу HTTP .
Мы можем использовать аннотацию @ResponseStatus
, чтобы установить статус и причину в нашем HTTP-ответе:
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Actor Not Found")
public class ActorNotFoundException extends Exception {
// ...
}
Если это исключение возникает при обработке HTTP-запроса, ответ будет включать в себя статус HTTP, указанный в этой аннотации.
Одним из недостатков подхода @ResponseStatus
является то, что он создает тесную связь с исключением. В нашем примере все исключения типа ActorNotFoundException
будут генерировать в ответе одно и то же сообщение об ошибке и код состояния.
3. Исключение состояния ответа
ResponseStatusException
— это программная альтернатива @ResponseStatus
и базовый класс для исключений, используемых для применения кода состояния к ответу HTTP. Это исключение RuntimeException
, поэтому его не требуется явно добавлять в сигнатуру метода.
Spring предоставляет 3 конструктора для генерации ResponseStatusException:
ResponseStatusException(HttpStatus status)
ResponseStatusException(HttpStatus status, java.lang.String reason)
ResponseStatusException(
HttpStatus status,
java.lang.String reason,
java.lang.Throwable cause
)
ResponseStatusException,
аргументы конструктора:
- status — статус HTTP, установленный для ответа HTTP
- причина — сообщение, объясняющее исключение, установленное для ответа HTTP.
- причина —
Throwable
причинаResponseStatusException
Примечание: в Spring HandlerExceptionResolver
перехватывает и обрабатывает любое исключение, сгенерированное и не обработанное контроллером.
Один из этих обработчиков, ResponseStatusExceptionResolver,
ищет любые ResponseStatusException
или необработанные исключения, аннотированные @ResponseStatus
, а затем извлекает код и причину состояния HTTP и включает их в ответ HTTP.
3.1. Преимущества ResponseStatusException
Использование ResponseStatusException
имеет несколько преимуществ:
- Во-первых, исключения одного и того же типа могут обрабатываться отдельно, а в ответах могут быть установлены разные коды состояния, что уменьшает тесную связь.
- Во-вторых, это позволяет избежать создания ненужных дополнительных классов исключений.
- Наконец, он обеспечивает больший контроль над обработкой исключений, поскольку исключения можно создавать программно.
4. Примеры
4.1. Сгенерировать исключение ResponseStatusException
Теперь давайте посмотрим на пример, который генерирует ResponseStatusException
:
@GetMapping("/actor/{id}")
public String getActorName(@PathVariable("id") int id) {
try {
return actorService.getActor(id);
} catch (ActorNotFoundException ex) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Actor Not Found", ex);
}
}
Spring Boot предоставляет сопоставление по умолчанию / error
, возвращая ответ JSON со статусом HTTP.
Вот как выглядит ответ:
$ curl -i -s -X GET http://localhost:8081/actor/8
HTTP/1.1 404
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 26 Dec 2020 19:38:09 GMT
{
"timestamp": "2020-12-26T19:38:09.426+00:00",
"status": 404,
"error": "Not Found",
"message": "",
"path": "/actor/8"
}
Начиная с версии 2.3, Spring Boot не включает сообщение об ошибке на странице ошибки по умолчанию. Причина в том, чтобы снизить риск утечки информации клиенту **
**
Чтобы изменить поведение по умолчанию, мы можем использовать свойство server.error.include-message
.
Давайте установим всегда
и посмотрим, что произойдет:
$ curl -i -s -X GET http://localhost:8081/actor/8
HTTP/1.1 404
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 26 Dec 2020 19:39:11 GMT
{
"timestamp": "2020-12-26T19:39:11.426+00:00",
"status": 404,
"error": "Not Found",
"message": "Actor Not Found",
"path": "/actor/8"
}
Как мы видим, на этот раз ответ содержит сообщение об ошибке «Актер не найден» .
4.2. Другой код состояния — тот же тип исключения
Теперь давайте посмотрим, как другой код состояния устанавливается для ответа HTTP при возникновении исключения того же типа:
@PutMapping("/actor/{id}/{name}")
public String updateActorName(
@PathVariable("id") int id,
@PathVariable("name") String name) {
try {
return actorService.updateActor(id, name);
} catch (ActorNotFoundException ex) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "Provide correct Actor Id", ex);
}
}
Вот как выглядит ответ:
$ curl -i -s -X PUT http://localhost:8081/actor/8/BradPitt
HTTP/1.1 400
...
{
"timestamp": "2018-02-01T04:28:32.917+0000",
"status": 400,
"error": "Bad Request",
"message": "Provide correct Actor Id",
"path": "/actor/8/BradPitt"
}
5. Вывод
В этом кратком руководстве мы обсудили, как создать исключение ResponseStatusException
в нашей программе.
Мы также подчеркнули, что с программной точки зрения это лучший способ установить коды состояния HTTP в HTTP-ответе, чем аннотация @ResponseStatus
.
Как всегда, полный исходный код доступен на GitHub .