【问题标题】:Spring WebFlux - statusCode is null in a WebFilterSpring WebFlux - WebFilter 中的 statusCode 为空
【发布时间】:2019-03-11 02:31:03
【问题描述】:

目前正在使用 Spring Boot 2.0.4 开发一个 WebFilter,用于在 Spring WebFlux 应用程序中记录 HTTP 请求和响应信息(URL、响应状态代码、持续时间等)。

工作正常,只是 exchange.getResponse().getStatusCode() 保持为空

尝试了两种不同的filter(ServerWebExchange exchange, WebFilterChain chain),第一个:

return chain.filter(exchange).doAfterTerminate(
        () -> System.out.println("Status=" + exchange.getResponse().getStatusCode()));

第二个:

    Mono<Void> filtered = chain.filter(exchange);
    exchange.getResponse().beforeCommit(() -> {
        System.out.println("Status=" + exchange.getResponse().getStatusCode());
        return Mono.empty();
    });
    return filtered;

还尝试了过滤器上的各种顺序:无、@Order(100000)、@Order(-100000)。

状态码保持为空。

什么是正确的实现方式?

更新 1

基于 KevH 解决方案编写了一个简约的工作示例,请参阅 https://github.com/fbeaufume/webflux-filter-sample 但它还没有工作,状态仍然为空。 MWE 公开了两个 REST 端点:/hello 和 /pause/1000(暂停 1 秒)。

注意,当调用暂停端点日志时:

11:06:20.644  INFO 9536 --- [ctor-http-nio-2] com.adeliosys.sample.LogFilter           : Request [/pause/1000] started, traceId [bb3fe67d-170b-4070-837d-816fe1420a1f]
11:06:20.673  INFO 9536 --- [ctor-http-nio-2] com.adeliosys.sample.HelloController     : Pausing for 1000 msec
11:06:21.683  INFO 9536 --- [     parallel-2] com.adeliosys.sample.LogFilter           : Request [/pause/1000] completed, statusCode [null], time [1039], traceId [bb3fe67d-170b-4070-837d-816fe1420a1f]
11:06:21.684  INFO 9536 --- [     parallel-2] com.adeliosys.sample.HelloController     : Paused for 1000 msec

我很惊讶过滤器的第二条消息显示在端点的第二条消息之前。

更新 2

使用 doAfterTerminate(或类似方法)的过滤器实现似乎是正确的,但这只有使用使用 ResponseEntity 的 REST 控制器方法才能正确检索 HTTP 响应状态在返回类型中。

不支持(即状态为空):voidMono&lt;Void&gt;StringMono&lt;String&gt;MyBeanMono&lt;MyBean&gt; 等。

支持(即状态为 200):ReponseEntity&lt;Void&gt;Mono&lt;ResponseEntity&lt;Void&gt;&gt;ReponseEntity&lt;String&gt;Mono&lt;ResponseEntity&lt;String&gt;&gt;ReponseEntity&lt;MyBean&gt;Mono&lt;ResponseEntity&lt;MyBean&gt;&gt; 等。

错误?

Spring Boot 2.0.5 具有相同的行为。

更新 3

打开一个关于该主题的问题,请参阅https://jira.spring.io/browse/SPR-17368

【问题讨论】:

    标签: java spring-boot spring-webflux


    【解决方案1】:

    你可以试试doAfterSuccessOrError

    @Override
        public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
            String traceId = UUID.randomUUID().toString();
            long startTime = System.currentTimeMillis();
            String path = exchange.getRequest().getURI().getPath();
            System.out.printf("Request[%s] started, trace_id[%s]", path, traceId);
    
            return chain.filter(exchange)
                    .doAfterSuccessOrError((r, t) -> {
                        System.out.printf("Request[%s], completed, status_code[%s], time[%d], trace_id[%s]", path,
                                exchange.getResponse().getStatusCode(), System.currentTimeMillis() - startTime, traceId);
                    })
                    .subscriberContext(Context.of(String.class, traceId));
        }
    

    样本输出

    请求[/logrequest] 开始, trace_id[b45b550a-b9ad-4323-a850-cb085a78a086] 请求[/logrequest], 完成,状态码[202],时间[41], trace_id[b45b550a-b9ad-4323-a850-cb085a78a086]

    编辑:不确定为什么这不起作用,但这里有两个解决方法 两者都有一个 ResponseEntity

    @GetMapping("/hello")
        public Mono<ResponseEntity<String>> publicHello() {
            return Mono.just(ResponseEntity.ok("Hello world!"));
        }
    
        @GetMapping("/pause/{duration}")
        @ResponseStatus(HttpStatus.ACCEPTED)
        public Mono<Void> pause2(@PathVariable long duration) {
            LOGGER.info("Pausing for {} msec", duration);
            return (duration > 0 ? Mono.delay(Duration.ofMillis(duration)) : Mono.empty())
                    .then()
                    .doFinally(s -> LOGGER.info("Paused for {} msec", duration));
        }
    

    【讨论】:

    • 不行,状态还是空:Request[/pause2/1000], completed, status_code[null], time[1010], trace_id[7fa1d55c-d042-4e1c-9eb8-396816e19298]
    • 你能添加你的响应处理程序吗?我怀疑这不是网络过滤器。或者最基本的 GET 请求,看看是否有效。从上面可以看出,它确实有效。
    • 在帖子中添加了更新 1,带有 MWE。感谢您的时间。 :)
    • 感谢您提供额外信息。在“/hello”中使用 ResponseEntity 可以修复过滤器中的空状态。但是您对“/pause/{duration}”的提议将无法按原样工作,因为没有人订阅 Mono,因此不使用延迟。原来我的第一个过滤器是正确的。只是它不支持所有 WebFlux 返回类型... WebFlux bug?更多更新即将到来。
    • @FlorianBeaufumé 您询问了如何在过滤器中获取响应状态,使用 @ResponseStatus(200) 更新您的处理程序等,它应该可以工作。
    猜你喜欢
    • 1970-01-01
    • 2022-01-11
    • 2018-11-27
    • 2021-07-27
    • 2021-10-26
    • 2018-04-05
    • 1970-01-01
    • 2019-09-23
    • 2019-01-15
    相关资源
    最近更新 更多