상황이 어떤가 살펴보자.
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
해서
사용할 수 있는 것이다.