괴발나라

[Spring 🌱] 컨트롤러 메서드에 매핑되기 전에 Request URI 조작하기 본문

프레임워크 & 라이브러리/Spring 🌱

[Spring 🌱] 컨트롤러 메서드에 매핑되기 전에 Request URI 조작하기

괴발맨 2022. 3. 1. 16:04
웹 애플리케이션을 개발하다 보면 URL을 암호화하여 클라이언트와 주고받아야 하는 경우가 있다.
클라이언트에서 URL 을 암호화하여 HTTP API를 호출하면 서버에서 그 URL을 복호화하여 처리해야 한다.
많은 시도 끝에 한가지 방법을 알아내어 공유하고자 한다.

URL 복호화를 Spring Interceptor 혹은 HandlerMethodArguementResolver 혹은 Converter 로 처리하려고 했으나,

다음과 같은 문제가 있었다.

 - 암호화된 것은 문자열(String)일텐데, 컨트롤러 메서드에서는 그 파라미터의 타입이 Integer인 경우 NumberFormatException 이 발생한다. 

 - 이는 Interceptor, HandlerMethodArguementResolver , Converter 에 도달하기 전에 발생하는 문제이기 때문에 

Request 핸들링 레이어에서 최상위에 있는 Filter로 처리해야 했다.

 

Filter를 구현하면, doFilter() 메서드를 이용해 ServletRequest의 정보를 얻어낼 수 있다.

하지만 ServletRequest 객체를 조작할 수는 없기 때문에, 스프링에서 제공하는 HttpServletRequestWrapper를 상속하여 사용했다.

 

코드를 직접 까보지는 않았지만,

Request URL 을 참고하여 그 요청을 처리할 특정 컨트롤러의 메서드를 찾을 때 

HttpServletRequestgetRequestURI() 메서드를 사용하는 듯 하다.

그래서 HttpServletRequestWrapperServletRequest 를 감싸고,

getRequestURI() 메서드를 오버라이딩하여 URL 복호화 문제를 해결했다.

@Slf4j
@Component
@Order(0)
public class CustomFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 클라이언트로부터 온 ServletRequest 객체를 HttpServletRequestWrapper를 상속한 클래스로 감싼 후 다음 필터로 보낸다. 
        chain.doFilter(new CustomRequestWrapper((HttpServletRequest) request), response);
    }
    
	// HttpServletRequestWrapper 를 상속함
    private static class CustomRequestWrapper extends HttpServletRequestWrapper {

        public CustomRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        @Override
        public String getRequestURI() {
        	// 요청 URL 을 복호화하여 리턴한다.
            return decryptUrl(super.getRequestURI());
        }
    }
}​

 

주의할 점은 다음과 같다.

나는 처음에 request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE)

메서드를 이용해 URL 파라미터 (PathVariable)를 얻은 후,

그것에 대하여 복호화 처리를 하려고 했으나,

요청이 처리될때, 즉 Controller에 도착하기 전까지는 위의 메서드가 null을 반환하고

Controller에서 요청 처리 후 응답 시에만 위의 메서드가 제대로된 값을 반환하는 것을 확인하였다. 

정확한 이유는 아직 알지 못한다.