You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot WebFlux自定义端点触发Mono Cancel Signal问题咨询

问题分析与解决方案

绝对不是预期行为,你遇到的是Spring Boot 2.1.x版本中WebFlux与Servlet容器交互的一个已知问题,下面给你拆解原因和解决办法:

为什么会出现这个差异?

在Spring Boot 2.1.x的WebFlux Servlet适配层中,当处理自定义端点的响应时,Servlet容器(比如默认的Tomcat)会在响应内容写入完成后,提前终止异步请求上下文,这会导致Reactive流中的Mono收到Cancel信号,而不是正常的onComplete信号。

而Actuator端点的处理逻辑不同:它的响应处理完全在Reactive栈内完成,没有被Servlet容器的异步机制提前中断,所以能正常触发doAfterSuccessOrErroronComplete信号。

你的代码里,doAfterSuccessOrError只会在Mono发出onSuccessonError信号时执行,而Cancel信号只会触发doFinally,这就是为什么自定义端点只输出Status: cancel的原因。

怎么解决?

方案1:升级Spring Boot版本(推荐)

这个问题在Spring Boot 2.2.x及以上版本中已经被官方修复,优化了Reactive流与Servlet容器的交互逻辑,确保信号能正确传递。只需要把parent的版本改成2.2.0.RELEASE或更高,再重新测试,自定义端点就会和Actuator端点一样输出:

Only actuators come to here. Status: onComplete

方案2:调整端点返回逻辑(如果无法升级)

如果暂时不能升级版本,可以修改自定义端点的返回方式,避免容器提前中断流:

@GetMapping("/hello")
public Mono<String> probe() {
    // 用Mono.just代替fromCallable,让响应流更稳定
    return Mono.just("world")
            // 可选:添加cancel信号的处理逻辑
            .doOnCancel(() -> LOGGER.info("Cancel signal caught, but we can handle it here"));
}

或者,你也可以在WebFilter中调整逻辑,用doOnTerminate代替doAfterSuccessOrError,它会在任何终止信号(包括cancel、success、error)时触发:

@Bean
public WebFilter newFilter() {
    return (exchange, chain) -> chain.filter(exchange)
            .doFinally(signalType -> {
                LOGGER.info("Status: {}", signalType);
            })
            .doOnTerminate(() -> {
                LOGGER.info("This will run for all endpoints, including canceled ones");
            });
}

内容的提问来源于stack exchange,提问作者andrericos

火山引擎 最新活动