Functional Endpoints[Serving Resources,Running a Server,Filtering Handler Functions]

2024. 10. 13. 21:00Spring Framework/Web on Servlet Stack

Spring Web MVC의 WebMvc.fn에서 제공하는 RouterFunction은 웹 애플리케이션에서 요청을 처리하기 위한 함수형 프로그래밍 모델입니다. 이 모델은 함수형 스타일을 사용하여 HTTP 요청을 처리하는 방식을 제공하며, 여러 유연한 기능들을 포함합니다. 이번 설명에서는 리소스 제공, 서버 실행, 필터 적용 등의 주요 개념을 상세히 다루겠습니다.

1. 리소스 제공 (Serving Resources)

RouterFunction을 사용하면 정적 리소스를 제공하거나 특정 조건에 맞는 요청을 리소스로 리디렉션할 수 있습니다. 예를 들어, SPA(Single Page Application)에서 리디렉션을 통해 단일 진입점(예: index.html)으로 모든 요청을 처리하는 경우 유용합니다.

리소스로 리디렉션

특정 요청을 처리할 때, 조건에 따라 리소스로 리디렉션할 수 있습니다. SPA에서 모든 비-API 요청을 index.html로 리디렉션하는 방식이 대표적입니다.

ClassPathResource index = new ClassPathResource("static/index.html");
List<String> extensions = Arrays.asList("js", "css", "ico", "png", "jpg", "gif");

// /api/** 경로나 확장자가 js, css, ico 등이 아닌 경우에만 index.html로 리디렉션
RequestPredicate spaPredicate = path("/api/**")
    .or(path("/error"))
    .or(pathExtension(extensions::contains)).negate();

RouterFunction<ServerResponse> redirectToIndex = RouterFunctions.route()
    .resource(spaPredicate, index)
    .build();
  • RequestPredicate: /api/**, /error 경로 이외의 요청이거나 지정된 확장자가 포함되지 않는 요청을 처리하는 조건을 정의합니다.
  • resource(): 리소스를 반환하는 함수입니다. 여기서는 요청을 index.html로 리디렉션합니다.

루트 경로에서 리소스 제공

루트 경로 또는 지정된 경로에서 정적 리소스를 제공할 수 있습니다. 예를 들어, /resources/**로 시작하는 모든 요청에 대해 public-resources/ 디렉토리의 리소스를 제공할 수 있습니다.

Resource location = new FileSystemResource("public-resources/");
RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
  • resources(): 특정 경로 패턴과 루트 위치를 기반으로 리소스를 제공하는 라우터를 생성합니다.

2. 서버 실행 및 라우팅 설정

WebMvc.fn에서 작성된 RouterFunction은 일반적으로 Spring의 DispatcherHandler 또는 DispatcherServlet과 함께 동작합니다. 이를 위해 MVC 설정에서 필요한 구성 요소들을 정의하고, 라우터 함수를 Bean으로 등록하여 Spring이 이를 감지하고 사용할 수 있도록 합니다.

Spring 설정 클래스

@Configuration
@EnableMvc
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public RouterFunction<?> routerFunctionA() {
        // 라우터 함수 정의
    }

    @Bean
    public RouterFunction<?> routerFunctionB() {
        // 라우터 함수 정의
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 메시지 변환기 설정
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // CORS 설정
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // 뷰 리졸버 설정
    }
}
  • RouterFunctionMapping: Spring에서 여러 RouterFunction<?> Bean을 감지하고 결합합니다. 여러 라우터 함수를 결합해 요청을 처리하는 데 사용됩니다.
  • HandlerFunctionAdapter: DispatcherHandlerHandlerFunction을 호출할 수 있도록 어댑터 역할을 합니다.
  • WebMvcConfigurer: 메시지 변환기, CORS 설정, 뷰 리졸버 등의 전역 설정을 할 수 있는 인터페이스입니다.

3. 필터링 (Filtering Handler Functions)

WebMvc.fn에서는 before, after, filter와 같은 메서드를 통해 특정 라우트에 필터를 적용할 수 있습니다. 이는 요청 전후에 특정 작업을 수행하거나, 보안 검사를 추가하는 등의 목적으로 사용됩니다.

Before & After 필터

  • before: 요청을 처리하기 전에 실행되는 필터입니다.
  • after: 요청을 처리한 후에 실행되는 필터입니다.
RouterFunction<ServerResponse> route = RouterFunctions.route()
    .path("/person", b1 -> b1
        .nest(accept(MediaType.APPLICATION_JSON), b2 -> b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople)
            .before(request -> ServerRequest.from(request)
                .header("X-RequestHeader", "Value")
                .build())) // 요청 전에 특정 헤더 추가
        .POST(handler::createPerson))
    .after((request, response) -> logResponse(response)) // 응답 후 로깅
    .build();
  • before(): 두 GET 요청에 대해 요청 전에 특정 헤더를 추가하는 필터입니다.
  • after(): 모든 요청이 처리된 후, 응답을 로깅하는 필터입니다.

Filter 메서드

filter() 메서드는 요청 처리 전후에 특정 로직을 추가할 수 있는 강력한 기능입니다. 보안 검증이나 로깅을 처리할 수 있습니다.

SecurityManager securityManager = ...;

RouterFunction<ServerResponse> route = RouterFunctions.route()
    .path("/person", b1 -> b1
        .nest(accept(MediaType.APPLICATION_JSON), b2 -> b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople))
        .POST(handler::createPerson))
    .filter((request, next) -> {
        // 요청 경로에 대해 보안 검사를 수행
        if (securityManager.allowAccessTo(request.path())) {
            return next.handle(request);  // 요청 처리 계속 진행
        } else {
            return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();  // 인증 실패
        }
    })
    .build();
  • filter(): 요청이 들어올 때 보안 검사를 수행하고, 접근이 허용된 경우에만 다음 핸들러 함수를 호출합니다. 그렇지 않으면 401 Unauthorized 응답을 반환합니다.

4. CORS 지원 (Cross-Origin Resource Sharing)

WebMvc.fn에서도 CORS 지원을 제공하는 CorsFilter를 통해 Cross-Origin 요청을 처리할 수 있습니다. WebMvcConfigurer를 사용해 전역적으로 CORS 설정을 추가하거나, 특정 라우터 함수에 대해 CORS 규칙을 적용할 수 있습니다.

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
        .allowedOrigins("https://example.com")
        .allowedMethods("GET", "POST");
}

이 코드는 / 경로에 대한 모든 요청에 대해 특정 도메인에서 오는 요청을 허용하며, GET 및 POST 메서드를 사용할 수 있도록 설정합니다.

5. 필터의 순서 및 적용 범위

필터는 특정 경로에만 적용되거나, 특정 요청 전/후에만 동작하도록 세밀하게 설정할 수 있습니다. 예를 들어, 중첩된 경로에서만 적용되는 필터를 설정하거나, 특정 라우트에만 필터를 적용할 수 있습니다.

  • 필터는 순차적으로 실행되며, 여러 필터가 적용된 경우 차례대로 실행됩니다.
  • before, after와 같은 필터는 중첩된 라우트 내에서만 동작할 수 있습니다.

결론

  • RouterFunction을 통해 Spring Web MVC에서 요청을 처리하는 방식이 더욱 유연해집니다. 라우팅, 리소스 제공, 필터링 등의 작업을 함수형 스타일로 간결하게 표현할 수 있습니다.
  • Servin Resources 기능은 정적 파일 제공이나 리디렉션에 유용하며, SPA 애플리케이션에서 특히 많이 사용됩니다.
  • 필터를 통해 요청 전후에 보안 검증, 로깅 등의 작업을 추가할 수 있습니다.
  • Spring 설정을 통해 RouterFunction을 Spring Bean으로 등록하여 DispatcherServlet과 함께 사용할 수 있습니다.

'Spring Framework > Web on Servlet Stack' 카테고리의 다른 글

MVC Config  (0) 2024.10.14
Functional Endpoints  (0) 2024.10.13
RounterFunction  (0) 2024.10.13
HandlerFunction  (0) 2024.10.13
Functional Endpoints Overview  (0) 2024.10.13