Summry
본 문서에서는 404 NotFound의 Exception Handling 방법을 정리한다.
send me email if you have any questions.
기존 예외 처리 방법
Spring에서는 아래와 같이 ControllerAdvice로 @ExceptionHandler를 사용해 Error들을 Handling 할 수 있는데, 404는 다른 예외처리와 다르게 application.properties에 별도의 설정이 필요하다.</sapn>
@RestControllerAdvice
@Slf4j
public class VssExceptionHandler {
// 400
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public ResponseEntity<Map<String, String>> missingServletRequestParameterException(final MissingServletRequestParameterException e, HttpServletRequest req) {
HttpHeaders responseHeaders = new HttpHeaders();
HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
log.error("400 error, missingServletRequestParameterException")
Map<String, String> map = new HashMap<>();
map.put("error type", httpStatus.getReasonPhrase());
map.put("code", "400");
map.put("message", "잘못된 요청, 필수 파라미터가 누락되었습니다.");
return new ResponseEntity<>(map, responseHeaders, httpStatus);
}
}
application.properties 설정
spring.mvc.throw-exception-if-no-handler-found=true
// 이걸 쓰면 include File을 적용한 파일에 css가 오류가 생김
// 하지만 참고 포스팅에선 이것도 설정에 넣어줌.
spring.web.resources.add-mappings=false
throw-exception-if-no-handler-found
public class DispatcherServlet {
protected void doDispatch(...) throws Exception {
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
}
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (this.throwExceptionIfNoHandlerFound) {
throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
new ServletServerHttpRequest(request).getHeaders());
}
else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
}
DispatcherServlet의 doDispatch 메소드를 확인해보면, mappedHandler가 null인 경우 noHandlerFound 메소드가 실행된다. 메소드 내부를 보면 throwExceptionIfNoHandlerFound에 값에 따라, Exception을 throw하는 지의 여부가 결정된다. 기본 설정은 false 이기 때문에 프론트 404의 응답만을 보냈다.
- 이 옵션을 ture로 설정하면 해결 가능
add-mappings
add-mappings를 true로 설정하면 두 번의 요청(잘못된 URL 요청, ‘/error’ 요청)이 각각 SimpleUrlHandlerMapping, RequestMappingHandlerMapping에 의해 처리되기 때문에 throwExceptionIfNoHandlerFound를 true로 설정하더라도 NoHandlerFoundException예외가 발생하지 않는다.
- 여기서 /error 요청은 존재하지않는 API에 대한 요청을 정적자원에 대한 요청으로 보기 때문에 파일이 없다면 Spring 내부적으로 발생시키는 ‘/error’ URL을 뜻한다.
반면에 add-mappings을 false로 설정하면 스프링에서 기본적으로 제공하는 정적자원요청에 대한 매핑을 사용하지 않기 때문에 잘못된 URL로 요청하더라도 SimpleUrlHandlerMapping가 해당 요청을 받지 않고 정상적으로 NoHandlerFoundException을 발생시킵니다.
ExceptionHandler 생성
@RestControllerAdvice
@Slf4j
public class VssExceptionHandler {
// 404
@ExceptionHandler(NoHandlerFoundException.class)
protected ResponseEntity<Map<String, String>> noHandlerFoundException(NoHandlerFoundException e, HttpServletRequest req) {
HttpHeaders responseHeaders = new HttpHeaders();
HttpStatus httpStatus = HttpStatus.NOT_FOUND;
log.error("400 error, NoHandlerFoundException")
Map<String, String> map = new HashMap<>();
map.put("error type", httpStatus.getReasonPhrase());
map.put("code", "404");
map.put("message", "잘못된 요청, 요청한 URI가 존재하지 않습니다.");
return new ResponseEntity<>(map, responseHeaders, httpStatus);
}
}
결과
404 Exception을 잘 핸들링 하는것을 볼 수 있다.
Reference
Spring REST API 404 응답 커스텀 - ydh6226
[Spring] 404 Error Custom하기 (@ExceptionHandler사용, NoHandlerFoundException Throw 안될때) - gillog
exceptionhandler를 이용한 404페오류페이지 처리 - ggujunhee