3 мин чтения
Почему Spring Boot возвращает 500 Internal Eror статус вместо 404 после обновления
Разбираеся почему после обновления Spring на версию 6.1+ в java приложении возникает ошибка 500 Internal Error вместо ожидаемого 404 Not Found для несуществующих API вызово и как это исправить.
Введение
В этой заметке рассмотрим почему возникает ошибка 500 Internal Error вместо ожидаемого 404 Not Found после обновления Spring или Spring Boot в java приложении и как это исправить. Данная статья касается ошибок при обновлении на версии Spring 6.1+ и Spring Boot 3.2+ с более ранних версий.
Что могло пойти не так?
После обновления версии Spring или Spring Boot в вашем приложении, вы можете заметить, что при запросе несуществующего ресурса возвращается 500 Internal Error вместо ожидаемого 404 статуса как это было ранее:
{
"timestamp": "2024-10-22T12:34:56.789Z",
"status": 404,
"error": "Not Found",
"path": "/adabracadabra"
}
В Spring 6.1+ и Spring Boot 3.2+ было внесено изменение в поведение обработки исключения NoResourceFoundException
в ResourceHttpRequestHandler
классе.
Теперь это исключение обрабатывается не spring-ом, а обработчиком ошибок, который задает разработчик.
Стандартной практикой является использование @ExceptionHandler
аннотации для обработки исключений в контроллерах, и в случае неожидаемой ошибки возвращать 500 статус.
Так например в вашем коде может быть примерно такой обработчик по умолчанию:
@ExceptionHandler(Exception.class)
public ResponseEntity handleAll(Exception ex, WebRequest request) {
log.error(ex.getMessage(), ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}
Когда в приложении происходит любое исключение, этот метод перехватывает его, логирует и возвращает ответ с кодом 500 и сообщением об ошибке.
В новой версии Spring NoResourceFoundException
тоже попадает в этот обработчик, и вместо стандартного 404 возвращается 500 статус.
Как исправить?
Для исправления данной проблемы, необходимо добавить обработчик исключения NoResourceFoundException
в контроллере и вернуть 404 статус или создать отдельный обратчик исключения NoResourceFoundException
:
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import java.time.Instant;
@Slf4j
@ControllerAdvice
public class CustomExceptionHandler {
// ...
@ExceptionHandler(NoResourceFoundException.class)
public ResponseEntity<CustomErrorResource> handleNoResourceFoundException(NoResourceFoundException exception) {
log.error("Resource not found", exception);
CustomErrorResource resource = CustomErrorResource.builder()
.timestamp(Instant.now().toString())
.status(exception.getStatusCode().value())
.error(exception.getMessage())
.path(exception.getResourcePath())
.build();
return ResponseEntity
.status(exception.getStatusCode())
.body(resource);
}
@Data
@Builder
public static class CustomErrorResource {
private String timestamp;
private int status;
private String error;
private String path;
}
// ...
}
Теперь статус ошибки и тело ответа приобретает прежний вид.
PROFIT!
Полезные ссылки
- Spring 6.1 / Spring Boot 3.2.0 Changelog
- NoResourceFoundException docs
- ExceptionHandler docs
- Spring boot 404 Not Found behavior github issue