【问题标题】:How to do post-matching filter in webflux?如何在 webflux 中进行匹配后过滤?
【发布时间】:2018-05-28 06:00:15
【问题描述】:

众所周知,在球衣中,我们有匹配前过滤器和匹配后过滤器。

我想知道如何在 webflux 应用程序中使用 WebFilter 获得类似的行为。

看起来 WebFilter 有点像预匹配过滤器,无论@RestController 中是否找到资源,它都会被执行。

我的过滤器是这样的(从弹簧执行器中的指标过滤器复制):

@Component
@Order(100)
public class AppFilter1 implements WebFilter {

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

    return chain.filter(exchange).compose((call) -> filter(exchange, call));
}

private Publisher<Void> filter(ServerWebExchange exchange, Mono<Void> call) {

    System.out.println("Start AppFilter1 in thread:" + Thread.currentThread().getId() + "..........");
    ServerHttpResponse response = exchange.getResponse();
    return call.doOnSuccess((done) -> success(exchange)).doOnError((cause) -> {
        if (response.isCommitted()) {
            error(exchange, cause);
        } else {
            response.beforeCommit(() -> {
                error(exchange, cause);
                return Mono.empty();
            });
        }
    });
}

private void success(ServerWebExchange exchange) {

    System.out.println("End AppFilter1 in thread:" + Thread.currentThread().getId() + "..............");

}

private void error(ServerWebExchange exchange, Throwable cause) {
    System.out.println("End AppFilter1 with Error in thread:" + Thread.currentThread().getId() + "...............");
}

}

添加我的控制器是这样的:

@RestController
public class ExampleController {

@GetMapping("/example")
public String example() {
    System.out.println("Example in thread:" + Thread.currentThread().getId());
    return "Example";
}
}

我可以看到,无论我访问 /example 还是 /notexist,过滤器都会被执行

实际上我希望我的过滤器进行后匹配,只为 /example 执行。

更具体地说,我希望看到 /example 的控制台输出:

Start AppFilter1 in thread:....
Example in thread:.....
End AppFilter1 in thread:....

对于像 /notexist 这样不匹配的资源,根本没有控制台输出。

谢谢

里昂

【问题讨论】:

  • 一个 WebFilter 可以两者兼得;请完成你的问题并解释你想要达到的目标,一个代码 sn-p 显示你到目前为止所做的尝试以及为什么它不是你预期的结果。
  • 感谢您的回复!我刚刚用示例代码更新了这个问题。我是响应式新手,我想我可能会使用“compose”以外的其他运算符来实现我的目标。
  • 如果没有关于用例的更多信息(你想在那个过滤器中实现什么?),很难就操作员的选择提供指导。对于请求路径部分,您可以检查请求路径并仅在匹配特定路径时应用您的方法。
  • 我只想在 /example 之前做一些事情,但我不希望我的 biz 逻辑被执行为像 /abcd 这样不存在的资源。检查过滤器中的请求路径可能不是一个好主意,因为我可能有数百个资源映射。这里,pre-matching 的意思是“无论资源是否匹配,都做某事”,post-matching 的意思是“只有当资源匹配时,才做某事”。
  • 期望的执行顺序:匹配前的过滤器--->定位资源----->匹配后的过滤器----->执行匹配的资源。如果没有匹配的资源,则不应调用匹配后过滤器。

标签: spring-boot spring-webflux


【解决方案1】:

Spring WebFlux WebFilter 类的运行级别与 Jersey 中的前/后匹配过滤器不同。它实际上更接近于 Servlet 过滤器。

WebFilter 不知道是什么在处理请求 - 它可能是控制器、提供静态资源的处理程序或任何其他自定义处理程序。

由于这里是 HTTP 级别,所以只检查请求路径以及响应状态是否不是“404 Not Found”。

由于您的问题没有提供有关您在这里尝试实现的目标的太多背景信息(业务逻辑?身份验证?日志记录?跟踪?任何涉及 I/O 的操作?),我真的不能说更多关于选择的信息反应堆操作员。

如果您想要一个仅在资源上运行的过滤器(如在 Jersey Resources 中),那么WebFilter 不是正确的选择,因为它在较低级别上运行(所有 HTTP 交换)。我认为 Spring Framework 中没有相应的基础设施。随意在 Spring Framework 中打开增强请求(这次提供有关您的用例的足够详细信息)。

【讨论】:

  • 感谢servlet过滤器的提醒。似乎 servlet 过滤器也没有“后匹配”概念。真正的用例可能是一些昂贵的东西,比如身份验证。例如,我不想支付额外费用来验证那些格式错误的/404/机器人请求。另一个例子可能是使用 WebFilter 提供一些上下文数据供以后使用,同样的,如果 404 不值得提前做一些事情
  • 我刚刚从其他人的代码中找到了 1 个示例,该示例是在实际服务 impl 使用它之前使用 WebFilter 创建上下文属性:github.com/rstoyanchev/context-holder/blob/master/src/main/java/…,我担心的是如果 404 请求进来,是WebFilter 付出了白费力气?
  • 我使用带有 spring boot 2.1.0 的反应器版本 3.2.0 和来自 https://github.com/rstoyanchev/context-holder/blob/master/src/main/java/com/example/context/RequestContextFilter.javacontextStart 方法不可用。这种在请求生命周期中保存请求上下文数据的能力是否已经发布?我想使用 webfilter 记录目的来保存请求上下文信息。
  • @nanachimi 请再问一个问题,cmets 不是为此量身定制的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-13
  • 2021-08-03
相关资源
最近更新 更多