1. Введение
Используя Spring, у нас обычно есть много способов достичь одной и той же цели, включая точную настройку HTTP-ответов.
В этом кратком руководстве мы увидим, как установить тело, статус и заголовки HTTP-ответа с помощью ResponseEntity
.
2. Сущность ответа
ResponseEntity
представляет весь ответ HTTP: код состояния, заголовки и тело . В результате мы можем использовать его для полной настройки HTTP-ответа.
Если мы хотим его использовать, мы должны вернуть его из конечной точки; Весна позаботится об остальном.
ResponseEntity
— это универсальный тип. Следовательно, мы можем использовать любой тип в качестве тела ответа:
@GetMapping("/hello")
ResponseEntity<String> hello() {
return new ResponseEntity<>("Hello World!", HttpStatus.OK);
}
Поскольку мы указываем статус ответа программно, мы можем возвращать разные коды статуса для разных сценариев:
@GetMapping("/age")
ResponseEntity<String> 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);
}
Кроме того, мы можем установить заголовки HTTP:
@GetMapping("/customHeader")
ResponseEntity<String> customHeader() {
HttpHeaders headers = new HttpHeaders();
headers.add("Custom-Header", "foo");
return new ResponseEntity<>(
"Custom header set", headers, HttpStatus.OK);
}
Кроме того, ResponseEntity
предоставляет два вложенных интерфейса компоновщика : HeadersBuilder
и его субинтерфейс BodyBuilder
. Поэтому мы можем получить доступ к их возможностям через статические методы ResponseEntity
.
Самый простой случай — это ответ с телом и кодом ответа HTTP 200:
@GetMapping("/hello")
ResponseEntity<String> hello() {
return ResponseEntity.ok("Hello World!");
}
Для самых популярных кодов состояния HTTP мы получаем статические методы:
BodyBuilder accepted();
BodyBuilder badRequest();
BodyBuilder created(java.net.URI location);
HeadersBuilder<?> noContent();
HeadersBuilder<?> notFound();
BodyBuilder ok();
Кроме того, мы можем использовать методы состояния BodyBuilder (состояние HttpStatus)
и состояния BodyBuilder (состояние int)
для установки любого состояния HTTP.
Наконец, с помощью ResponseEntity<T> BodyBuilder.body(T body)
мы можем установить тело ответа HTTP:
@GetMapping("/age")
ResponseEntity<String> 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));
}
Мы также можем установить собственные заголовки:
@GetMapping("/customHeader")
ResponseEntity<String> customHeader() {
return ResponseEntity.ok()
.header("Custom-Header", "foo")
.body("Custom header set");
}
Поскольку BodyBuilder.body()
возвращает ResponseEntity
вместо BodyBuilder,
это должен быть последний вызов.
Обратите внимание, что с помощью HeaderBuilder
мы не можем установить какие-либо свойства тела ответа.
При возврате объекта ResponseEntity<T>
из контроллера мы можем получить исключение или ошибку при обработке запроса и хотели бы вернуть информацию об ошибке пользователю, представленному в виде некоторого другого типа, скажем, E .
Spring 3.2 поддерживает глобальный @ExceptionHandler
с новой аннотацией @ControllerAdvice
, которая обрабатывает такие сценарии. Для более подробной информации обратитесь к нашей существующей статье здесь .
Хотя ResponseEntity
очень мощен, мы не должны злоупотреблять им. В простых случаях есть другие варианты, которые удовлетворяют наши потребности и приводят к более чистому коду.
3. Альтернативы
3.1. @ResponseBody
В классических приложениях Spring MVC конечные точки обычно возвращают обработанные HTML-страницы. Иногда нам нужно только вернуть фактические данные; например, когда мы используем конечную точку с AJAX.
В таких случаях мы можем пометить метод обработчика запроса с помощью @ResponseBody
, и Spring обрабатывает результирующее значение метода как само тело ответа HTTP .
Для получения дополнительной информации эта статья является хорошей отправной точкой .
3.2. @ResponseStatus
Когда конечная точка успешно возвращается, Spring предоставляет ответ HTTP 200 (ОК). Если конечная точка выдает исключение, Spring ищет обработчик исключений, который сообщает, какой статус HTTP использовать.
Мы можем пометить эти методы с помощью @ResponseStatus, и поэтому Spring возвращает с пользовательским HTTP-статусом .
Дополнительные примеры см. в нашей статье о пользовательских кодах состояния .
3.3. Управляйте ответом напрямую
Spring также позволяет нам напрямую обращаться к объекту javax.servlet.http.HttpServletResponse ;
нам нужно только объявить его как аргумент метода:
@GetMapping("/manual")
void manual(HttpServletResponse response) throws IOException {
response.setHeader("Custom-Header", "foo");
response.setStatus(200);
response.getWriter().println("Hello World!");
}
Поскольку Spring предоставляет абстракции и дополнительные возможности поверх базовой реализации, мы не должны манипулировать ответом таким образом .
4. Вывод
В этой статье мы обсудили несколько способов манипулирования ответом HTTP в Spring и рассмотрели их преимущества и недостатки.
Как обычно, примеры доступны на GitHub .