优秀的编程知识分享平台

网站首页 > 技术文章 正文

Spring WebFlux响应式编程之过滤器Filter

nanyue 2024-08-20 17:31:57 技术文章 8 ℃

概述

Filter过滤器的使用在Web应用程序中非常普遍,过滤器提供了一种在不改变Endpoint端点现有逻辑的情况下修改请求或响应的方法。

Maven Dependency

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

端点(Endpoint)

引入过滤器之前,我们必须首先创建一些端点。WebFlux支持两种创建Endpoint的方法:基于注释和基于函数。

我们从基于注释的控制器开始:

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

对于函数控制器,我们必须首先创建一个端点处理器:

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

然后进行路由器配置映射:

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

WebFlux过滤器类型

WebFlux框架提供了两种类型的过滤器:WebFilters和HandlerFilterFunctions。

它们之间的主要区别是WebFilter实现适用于所有端点,HandlerFilterFunction实现仅适用于基于路由函数的端点。

  • WebFilter

比如实现一个WebFilter,用于向Response响应中添加新的消息头:

@Component
public class ExampleWebFilter implements WebFilter {
 
    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, 
      WebFilterChain webFilterChain) {
        
        serverWebExchange.getResponse()
          .getHeaders().add("web-filter", "web-filter-test");
        return webFilterChain.filter(serverWebExchange);
    }
}
  • HandlerFilterFunction

比如实现当“name”参数等于“test”时,将HTTP状态设置为FORBIDEN:

public class ExampleHandlerFilterFunction 
  implements HandlerFilterFunction<ServerResponse, ServerResponse> {
 
    @Override
    public Mono<ServerResponse> filter(ServerRequest serverRequest,
      HandlerFunction<ServerResponse> handlerFunction) {
        if (serverRequest.pathVariable("name").equalsIgnoreCase("test")) {
            return ServerResponse.status(FORBIDDEN).build();
        }
        return handlerFunction.handle(serverRequest);
    }
}

测试验证

在WebFlux框架中提供WebTestClient,可以用于测试对端点的HTTP调用。

  • 以下是基于注释的端点测试用例:
@Test
public void whenUserNameIsBaeldung_thenWebFilterIsApplied() {
    EntityExchangeResult<String> result = webTestClient.get()
      .uri("/users/webflux")
      .exchange()
      .expectStatus().isOk()
      .expectBody(String.class)
      .returnResult();

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

@Test
public void whenUserNameIsTest_thenHandlerFilterFunctionIsNotApplied() {
    webTestClient.get().uri("/users/test")
      .exchange()
      .expectStatus().isOk();
}
  • 以下是基于路由函数的端点测试用例:
@Test
public void whenPlayerNameIsBaeldung_thenWebFilterIsApplied() {
    EntityExchangeResult<String> result = webTestClient.get()
      .uri("/players/webflux")
      .exchange()
      .expectStatus().isOk()
      .expectBody(String.class)
      .returnResult();

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

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

结论

过滤器Filter常用于全局请求和响应日志记录、身份验证等,WebFilter选型比较适合非侵入式的功能增强。

Tags:

最近发表
标签列表