본문 바로가기
Baeldung번역&공부/Spring-Reactive

스프링-웹플럭스-필터(Spring WebFlux Filters)

by ms727 2025. 2. 15.

원본 글: https://www.baeldung.com/spring-webflux-filters

 

Spring Webflux Filters | Baeldung

Learn how to modify requests and responses using Spring Webflux Filters

www.baeldung.com

 

엔드포인트를 수정하지 않고 request나 response를 수정하기 위해 filter는 웹 애플리케이션에서 많이 사용되고 있습니다.

 

이 가이드에서는 웹 플럭스를 이용해서 이를 구현하는 방법을 설명합니다.

 

1. Maven Dependency

먼저, WebFlux에대한 의존성을 추가합니다.

 

//gradle
implementation 'org.springframework.boot:spring-boot-starter-webflux'

//maven
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

 

 

2. Endpoints

어노테이션기반, 함수기반으로 만들어진 연습용 엔드포인트를 만듭니다.

 

어노테이션 기반 컨트롤러입니다.

 

@RestController
public class ExampleController {

    @GetMapping("/users/{name}")
    public Mono<String> getUser(@PathVariable String name) {
        return Mono.just(name);
    }

}

 

다음은 함수기반 엔드포인트를 위한 핸들러를 만듭니다.

 

@Component
public class ExampleHandler {

    public Mono<ServerResponse> getName(ServerRequest request) {
        Mono<String> name = Mono.just(request.pathVariable("name"));
        return ServerResponse.ok().body(name, String.class);
    }
}

 

라우터를 통해 두 정보를 연결시켜줍니다.

 


public class ExampleRouter {

    @Bean
    public RouterFunction<ServerResponse> route(ExampleHandler exampleHandler) {
        return RouterFunctions
                .route(GET("/players/{name}"), exampleHandler::getName)
                .filter(new ExampleHandlerFilterFunction());
    }
}

 

여기서 ExampleHandlerFilterFunction은 뒤에서 살펴보도록 합니다. 

 

3. Types of WebFlux Filters

웹 플럭스 프레임워크는 WebFilter와 HandlerFilterFunctions라는 2가지 종류의 필터를 제공합니다. 

 

WebFilter는 모든 엔드포인트에 대해 동작하고, HandlerFilterFunction은 Router기반(RouterFunction)에서만 동작합니다.

 

3.1 WebFilter

WebFilter를 통해서 response에 새로운 헤더를 추가하는 예제를 작성합니다. 모든 엔드포인트에 대해서 동작합니다.

 

@Component
public class ExampleWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        exchange.getResponse().getHeaders().add("web-filter", "web-filter-test");
        return chain.filter(exchange);
    }
}

 

3.2 HandlerFilterFunction

이 필터에서는 요청 파라미터(name)값이 "test"라면 FORBIDDEN Http 상태를 반환하는 로직을 추가합니다.

 

//제네릭 첫번째: HandlerFunction 반환타입, 두번째: filter함수가 반환하는 타입
public class ExampleHandlerFilterFunction implements HandlerFilterFunction<ServerResponse, ServerResponse> {
    @Override
    public Mono<ServerResponse> filter(ServerRequest request, HandlerFunction<ServerResponse> next) {
        if(request.pathVariable("name").equalsIgnoreCase("test")) {
            return ServerResponse.status(HttpStatus.FORBIDDEN).build();
        }
        return next.handle(request);
    }
}

 

4. Testing

 

WebTestClient를 통해서 필터기능을 테스트할 수 있습니다. 먼저 어노테이션 기반 엔드포인트 테스트를 진행하겠습니다.

 

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
public class ExampleWebFilterTest {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    public void whenUserNameIsMinseok_thenWebFilterIsApplied() {
        EntityExchangeResult<String> response = webTestClient.get()
                .uri("/users/minseok")
                .exchange()
                .expectStatus().isOk()
                .expectBody(String.class)
                .returnResult();
        Assertions.assertEquals("minseok", response.getResponseBody());
        Assertions.assertEquals("web-filter-test", response.getResponseHeaders().getFirst("web-filter"));
    }
    
	@Test
    public void whenUserNameIsTest_thenHandlerFilterFunctionIsNotApplied() {
        webTestClient.get().uri("/users/test")
                .exchange()
                .expectStatus().isOk();
    }
}

 

다음은 라우트기반 엔드포인트 테스트입니다.

 

@Test
public void whenPlayerNameIsMinseok_thenWebFilterIsApplied() {
    EntityExchangeResult<String> result = webTestClient.get()
            .uri("/players/minseok")
            .exchange()
            .expectStatus().isOk()
            .expectBody(String.class)
            .returnResult();

    Assertions.assertEquals("minseok", result.getResponseBody());
    Assertions.assertEquals("web-filter-test",
            result.getResponseHeaders().getFirst("web-filter"));
}

@Test
public void whenPlayerNameIsTest_thenHandlerFilterFunctionIsApplied() {
    webTestClient.get().uri("/players/test")
            .exchange()
            .expectStatus().isForbidden();
}

 

실행해보면 의도한대로 잘 동작함을 알 수 있습니다.

 

5. 결론

몇가지 코드를 확인해보며 WebFlux에서 필터가 어떤 종류가 있는지, 어떻게 동작하는지 확인해보았습니다.

 

예제코드: https://github.com/kkminseok/baeldung-test/blob/main/Spring-reactive/Spring-Webflux-Filter/src/test/java/com/my/springwebfluxfilter/ExampleWebFilterTest.java

 

baeldung-test/Spring-reactive/Spring-Webflux-Filter/src/test/java/com/my/springwebfluxfilter/ExampleWebFilterTest.java at main

baeldung-test. Contribute to kkminseok/baeldung-test development by creating an account on GitHub.

github.com

 

내 생각

 

가이드 자체가 친절한 편은 아니라(static import가 많아서) 몇개의 코드를 추가하였습니다.  

이 글을 통해서 라우트 방식, Controller를 이용한 일반적인 방식을 학습하였습니다.

특정 요청에 대한 필터는 라우트방식을 이용해서 하는편이 나을 것 같습니다.