概述
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选型比较适合非侵入式的功能增强。