WebFlux项目中如何获取Mono值?解决block()阻塞报错问题
解决Spring WebFlux中block()阻塞调用的问题
问题分析
你的代码中使用block()同步获取Mono<MapFile>和Mono<UserInfo>的结果,违反了WebFlux的非阻塞响应式编程原则。WebFlux运行在非阻塞IO线程(如reactor-http-nio-*)上,阻塞调用会占用线程资源、破坏异步链特性,最终触发报错。
修改方案
核心是移除所有block()调用,改用响应式操作符组合异步数据流,通过Mono.zip合并所有需要的异步结果,在flatMap中一次性获取数据并执行后续逻辑。
修改后的完整代码
public Mono<ServerResponse> downloadAttachment(final ServerRequest request) { String fileName = "prova_B400.png"; final Integer idPercorso = request.queryParam("idPercorso") .map(Integer::parseInt) .orElse(null); // 保存异步数据流,避免重复执行 Mono<UserInfo> userInfoMono = super.parseUserInfo(request); // 通过flatMap链式调用获取MapFile的Mono,全程无阻塞 Mono<MapFile> mapFileMono = userInfoMono.flatMap(userInfo -> silverMountainService(userInfo).getMapFile(idPercorso) ); // 合并所有需要的异步数据流:UserInfo、请求体、MapFile return Mono.zip(userInfoMono, request.bodyToMono(ObjectNode.class), mapFileMono) .flatMap(tuple -> { UserInfo userInfo = tuple.getT1(); // ObjectNode dto = tuple.getT2(); // 后续需要请求体时可启用 MapFile mapFile = tuple.getT3(); // 响应式调用下载方法 return silverMountainService(userInfo).downloadMappaPercorso( StorageType.parse(mapFile.storageType), mapFile.omniaClass, fileName ) .flatMap(fileResult -> ServerResponse.ok() .headers(h -> h.setContentDisposition( Optional.ofNullable(fileName) .filter(StringUtils::isNotBlank) .map(filename -> ContentDisposition.attachment().filename(filename).build()) .orElseGet(() -> ContentDisposition.inline().build()) )) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(BodyInserters.fromValue(fileResult.getContent())) ); }) .onErrorResume(CustomHttpException.class, assEx -> { log.error("Error({}): {}", assEx.getErrorId(), assEx.getMessage()); return ServerResponse.status(assEx.getHttpStatus()).bodyValue(String.format("ErrorID: %s", assEx.getErrorId())); }) .onErrorResume(Exception.class, ex -> { var errId = UUID.randomUUID().toString(); log.error(String.format("Error(%s) %s", errId, ex.getMessage()), ex); return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).bodyValue(String.format("ErrorID: %s", errId)); }); }
关键修改点说明
- 移除阻塞调用:将
super.parseUserInfo(request).block()改为保存Mono<UserInfo>实例,通过flatMap链式获取Mono<MapFile>,全程保持响应式异步特性。 - 合并异步结果:用
Mono.zip将三个独立的异步数据流合并为一个Tuple,在flatMap中一次性获取所有需要的数据,避免逐个阻塞获取。 - 避免重复执行:将
super.parseUserInfo(request)的结果存为变量,解决原代码中两次调用导致的重复执行问题。
内容的提问来源于stack exchange,提问作者bircastri
相关产品推荐
相关产品推荐

