
상황이 어떤가 살펴보자.
public abstract class SessionLogin implements HandlerInterceptor {
...
if (accessToken == null) {
throw new IllegalArgumentException("로그인이 필요합니다.");
}
...
}
위의 코드는 인터셉터에서 예외를 발생 시킨다.
하지만 이렇게 끝내면 500에러를 응답하게 된다.
스프링은 예외가 발생하면, WAS로 예외를 다시 전달한다.
그리고 WAS는 /error로 재요청한다. /error는 스프링이 기본으로 제공하는 api이다.
BasicErrorController.java가 정의한 컨트롤러이다.
이 컨트롤러를 타면, 스프링이 제공하는 기본 페이지를 응답하고, 500으로 반환하게 되는 것이다.
HandlerInterceptor와 HandlerExceptionResolver의 위치를 살펴보자.
출처 - **스프링 MVC 2편 - 백엔드 웹 개발 활용 기술**
DispatcherServlet → preHandler(HandlerInterceprot) → Controller → postHandler(HandlerInterceprot)DispatcherServlet → afterCompletion → 응답afterCompletion 전에 발생한 예외는 모두 DispatcherServlet으로 반환된다.afterCompletion은 모든 처리가 끝난 후 예외 정보, 요청, 응답 정보를 모두 받는 위치에 있기 때문이다.HandlerExceptionResolver은 핸들러에 연관된 예외를 핸들링 하기 위한 것이다.
preHandle에서 예외 발생@Controller, @RestController)ExceptionResolver가 예외 해결 시도preHandler에서 예외 발생/error로 재요청하며, 500 페이지 제공결국 핸들러가 존재하지 않았기 때문에 핸들링이 되지 않는 범위였던 것이었다.
그렇다면, 핸들러가 존재하지 않을 때는 어떻게 해야 HandlerExceptionResolver의 핸들링 대상이 될까?
getRequestDispatcher를 사용하여 forward를 사용한다. response.sendRedirect를 사용해도 되지만,forward를 선택했다.public abstract class SessionLogin implements HandlerInterceptor {
...
private boolean isAccessToken(HttpServletRequest request, HttpServletResponse response, String accessToken) throws ServletException, IOException {
if (accessToken != null) {
return true;
}
request.setAttribute("message", "로그인이 필요합니다.");
request.setAttribute("exception", "AuthenticationException");
request.getRequestDispatcher("/api/error").forward(request, response);
System.out.println("request = " + request);
return false;
}
}
...
}
@RestController
public class ErrorController {
@GetMapping("/api/error")
public void error(HttpServletRequest request) throws AuthenticationException {
String message = (String) request.getAttribute("message");
String exception = (String) request.getAttribute("exception");
if ("AuthenticationException".equals(exception)) {
throw new AuthenticationException(message);
}
}
}
이렇게 되면, 결국 컨트롤러에서 예외가 발생되기 때문에 HandlerExceptionResolver가 핸들링할 수 있게된다.
상황에 따라 다르겠지만, 현재 나의 상황에서 이유는 2가지가 있다.
재요청을 하여 네트워크를 두 번 탈 이유가 없다.message, exception을 ErrorController에서 사용해야 한다.JSP를 사용해봤다면 forward를 봤을수도 있고, 보지 못했을 수도 있다.
JSP에서 우리는 모델에 담긴 객체를 그대로 사용하게 되는데 이는 request.setAttribute로 서블릿이 담는 것이고,
이를 JSP로 forwarding해서 url 변경없이 JSP화면이 제공되고, JSP 페이지는 이를 request.getAttribte해서
사용할 수 있는 것이다.