Spring #4

황현근·2023년 7월 11일
0

Spring

목록 보기
4/6
post-thumbnail

📖 인터셉터(Interceptor)

'가로채다' 라는 의미가 있다.
위의 의미와 같이 Client에서 Server로 보낸 RequestController에 도달하기 전 가로채도록 하는 역할을 한다.
Dispatcher Servlet이 Controller를 호출하기 전 / 후에 인터셉터가 끼어들어 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다.

웹 컨테이너에서 동작하는 필터와 달리 인터셉터는 스프링 컨텍스트에서 동작한다.

디스패처 서블릿이 핸들러 매핑을 통해 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다.
여기서 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고,
인터셉터가 없다면 바로 컨트롤러를 실행한다.

실제로 Interceptor가 직접 Controller로 요청을 위임하는 것은 아니다.

💡 Interceptor 의 장점

  • 누락에 대한 위험 감수
  • 코드 재사용성을 증가 시켜 메모리 낭비, 서버 부하 감소 가 있다.

📌 Interceptor 의 메소드 종류

인터셉터를 추가하기 위해서 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현(implements) 해야 하며, 다음과 같은 메소드를 가진다.

public interface HandlerInterceptor {
 
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
// View의 모든 작업이 완료된 후 실행된다.
// 리소스를 반환해주기 적당한 메소드이다.
		return true;
	}
 
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
// Controller 가 실행 후 View 가 생성되기 이전에 호출한다.
// ModelAndView 를 통해 View 에 들어가는 데이터를 조작할 수 있다.
	}
 
	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
// Controller 가 호출되기 전에 실행된다.     // Controller 실행 전 처리할 작업이나 정보를 가공, 추가하는 경우 사용된다.
// return 값이 true 일 경우 정상적으로 Controller 로 접근하고
// false 일 경우 Controller 에 접근하지 않는다.
	}
  • preHandle()

    • Controller가 호출되기 전에 실행된다.
    • Controller 실행 전 처리할 작업이나 정보를 가공, 추가하는 경우 사용된다.
    • return 값이 true일 경우 정상적으로 Controller로 접근하고
    • false일 경우 Controller에 접근하지 않는다.

  • postHandle()

    • Controller가 실행 후 View가 생성되기 이전에 호출한다.
    • ModelAndView를 통해 View에 들어가는 데이터를 조작할 수 있다.

  • afterCompletion()

    • View의 모든 작업이 완료된 후 실행된다.
    • 리소스를 반환해주기 적당한 메소드이다.

사용 예시 LoginInterceptor

// 로그인된 사용자인지 검사할 인터셉터
public class LoginInterceptor implements HandlerInterceptor {
    // Controller 메소드 수행직전에 로그인된 사용자 인지 검증을 해서
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        // 세션 객체의 참조값을 얻어와서
        HttpSession session = request.getSession();
        String id = (String) session.getAttribute("id");
        // 만일 로그인을 하지 않았다면
        if (id == null) {
            // 로그인 페이지로 리다일렉트 이동시키고 false 를 리턴한다.

            // 원래 가려던 url 정보 읽어오기
            String url = request.getRequestURI();
            // GET 방식 전송 파라미터를 query 문자열로 읽어오기 ( a=xxx&b=xxx&c=xxx )
            String query = request.getQueryString();
            // 특수 문자는 인코딩을 해야한다.
            String encodedUrl;
            if (query == null) {// 전송 파라미터가 없다면
                encodedUrl = URLEncoder.encode(url);
            } else {
                // 원래 목적지가 /test/xxx.jsp 라고 가정하면 아래와 같은 형식의 문자열을 만든다.
                // "/test/xxx.jsp?a=xxx&b=xxx ..."
                encodedUrl = URLEncoder.encode(url + "?" + query);
            }

            // 3. 로그인을 하지 않았다면  /users/loginform 페이지로 리다일렉트 이동 시킨다. (HttpServletResponse)
            String cPath = request.getContextPath();
            response.sendRedirect(cPath + "/users/loginform?url=" + encodedUrl);
            return false;
        }
        // 로그인을 했다면 흐름을 이어간다.
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
        throws Exception {

    }
}


🤔 필터(Filter)와 인터셉터(Interceptor)의 차이 및 비교

필터는 RequestResponse를 조작할 수 있지만, 인터셉터는 조작할 수 없다.

public class MyFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        // 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(request, response);
    }
}

필터가 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해주어야 한다.
이때 request, response 객체를 넘겨주므로 우리가 원하는 request, response 객체를 넣어줄 수 있다.

하지만 인터셉터는 처리 과정이 필터와 다르다.

public class MyInterceptor implements HandlerInterceptor {
 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
    throws Exception {
        // Request, Response를 교체할 수 없고 boolean 값만 반환 가능
        return true;
    }
}

디스패처 서블릿이 여러 인터셉터 목록을 가지고 있고, 순차적으로 실행시킨다.
true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단된다.
그러므로 다른 request, response 객체를 넘겨줄 수 없다.

Filter 와 Interceptor 의 사용 사례

Filter 의 사용 사례

  • 보안 및 인증/인가 관련 작업
  • 모든 요청에 대한 로깅 또는 검사
  • 이미지/데이터 압축 및 문자열 인코딩
  • Spring과 분리되어야 하는 기능

필터는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다.
또한, 이미지나 데이터의 압축, 문자열 인코딩과 같이 웹 어플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다.

Interceptor 의 사용 사례

  • 세부적인 보안 및 인증/인가 공통 작업
  • API 호출에 대한 로깅 또는 검사
  • Controller로 넘겨주는 정보(데이터)의 가공

인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있다.

0개의 댓글