Если у меня есть контроллер Spring REST, подобный этому
@PostMapping(
value = "/configurations",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public CreateConfigurationResponse createConfiguration(
@RequestBody @Valid @NotNull final CreateConfigurationRequest request) {
// do stuff
}
и клиент вызывает эту конечную точку с неправильным типом носителя в заголовке Accept, тогда spring выдает HttpMediaTypeNotAcceptableException. Затем наш обработчик исключений ловит это и формирует ответ об ошибке Problem (rfc-7807).
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class HttpMediaTypeExceptionHandler extends BaseExceptionHandler {
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<Problem> notAcceptableMediaTypeHandler(final HttpMediaTypeNotAcceptableException ex,
final HttpServletRequest request) {
final Problem problem = Problem.builder()
.withType(URI.create("...."))
.withTitle("unsupported media type")
.withStatus(Status.NOT_ACCEPTABLE)
.withDetail("...error stuff..")
.build();
return new ResponseEntity<>(problem, httpStatus);
}
Но поскольку ответ об ошибке Problem должен быть отправлен обратно с типом носителя application/problem+json, то Spring считает это неприемлемым типом носителя и снова вызывает обработчик исключений HttpMediaTypeExceptionHandler и говорит, что тип носителя недопустим.
Есть ли способ в Spring остановить этот второй цикл в обработчике исключений, и хотя заголовок accept не включает тип мультимедиа application/problem+json, он все равно просто вернет его?
Как ни странно, он начал работать, когда я изменил оператор return с этого:
return new ResponseEntity<>(problem, httpStatus);
к этому:
return ResponseEntity
.status(httpStatus)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body(problem);
Я не уверен, как это заставляет это работать, но это работает.