在带响应体的WebFilter中使用Spring Data Reactive Repository saveAll()异常
问题分析与解决方案
问题原因
当处理器返回带响应体的ServerResponse时,客户端接收完响应体后可能立即断开连接,触发服务器端响应流的cancel()信号。你当前使用chain.filter(exchange).then(logMessage(exchange))的结构,then操作完全依附于主响应流:当主流被取消时,后续的saveAll流也会被强制取消,导致数据库保存操作中断。而无响应体的场景中,响应流会正常完成,then里的保存操作能顺利执行。
解决方案
有两种可靠方式确保日志保存操作不受响应流取消的影响:
方案1:利用响应提交前回调(确保数据保存后再发送响应)
将日志保存操作注册到响应提交前的回调中,无论响应是正常完成还是被取消,都会执行该操作,且会等待操作完成后再提交响应,保证数据能成功写入数据库:
修改LogWebFilter的filter方法:
@NonNull public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { // 注册响应提交前的回调,确保日志保存完成后再发送响应 exchange.getResponse().beforeCommit(() -> logMessage(exchange)); return chain.filter(exchange); }
方案2:异步执行日志操作(不阻塞响应发送)
如果不需要等待日志保存完成再返回响应,可以用doFinally在流结束(无论完成还是取消)时异步执行日志操作,脱离主响应流的生命周期:
@NonNull public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange) .doFinally(signalType -> { logMessage(exchange) .subscribeOn(Schedulers.boundedElastic()) .subscribe( null, err -> log.error("保存操作日志失败", err) ); }); }
额外检查
你的UserOperationLog实体类中isNew()始终返回true,这符合新增数据的场景,但需确保id字段配置了数据库自动生成规则(比如自增),否则可能导致保存失败。从无响应体场景的正常表现来看,这部分应该没有问题。
内容的提问来源于stack exchange,提问作者Peter Balogh
相关产品推荐
相关产品推荐

