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容器的异步机制提前中断,所以能正常触发doAfterSuccessOrError和onComplete信号。
你的代码里,doAfterSuccessOrError只会在Mono发出onSuccess或onError信号时执行,而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




