You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux文件下载API如何兼容空请求体?

Spring Boot WebFlux 文件下载API支持空请求体的解决方案

问题背景

我使用Spring Boot WebFlux构建了一个文件下载API,相关代码如下:

public Mono<ServerResponse> downloadAttachment(final ServerRequest request) {
    final var idPercorso = request.queryParam("idPercorso")
            .map(Integer::parseInt).orElse(null);
}

Mono<ServerResponse> additionalCalcualtions(MapFile mapFile, ServerRequest request){
    return Mono.zip(parseUserInfo(request), request.bodyToMono(ObjectNode.class))
            .flatMap(t -> {
                //var dto = t.getT2();
                return silverMountainService(t.getT1()).downloadMappaPercorso(StorageType.parse(mapFile.storageType),mapFile.omniaClass, mapFile.getFileName()
                        )
                        .flatMap(fileResult -> ServerResponse.ok()
                                .headers(h -> h.setContentDisposition(
                                        Optional.ofNullable(mapFile.getFileName())
                                                .filter(StringUtils::isNotBlank)
                                                .map(filename -> ContentDisposition.attachment().filename(mapFile.getFileName()).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));
            });
}

接口调用地址为:myUrl/downloadMappa?idPercorso=2

当前问题:当请求携带空JSON体{}时接口可正常工作,但不带请求体时会返回空响应,需要修改代码支持空请求体的场景。

解决方案

核心问题在于request.bodyToMono(ObjectNode.class)在无请求体时会生成一个空的Mono,导致Mono.zip因缺少其中一个输入值而无法触发后续逻辑,最终返回空响应。只需给获取请求体的逻辑添加空值兜底即可:

修改后的additionalCalcualtions方法代码:

Mono<ServerResponse> additionalCalcualtions(MapFile mapFile, ServerRequest request){
    // 给bodyToMono添加空值兜底,无请求体时返回null
    return Mono.zip(parseUserInfo(request), request.bodyToMono(ObjectNode.class).defaultIfEmpty(null))
            .flatMap(t -> {
                // var dto = t.getT2(); // 代码未用到请求体内容,null不影响逻辑
                return silverMountainService(t.getT1()).downloadMappaPercorso(StorageType.parse(mapFile.storageType),mapFile.omniaClass, mapFile.getFileName())
                        .flatMap(fileResult -> ServerResponse.ok()
                                .headers(h -> h.setContentDisposition(
                                        Optional.ofNullable(mapFile.getFileName())
                                                .filter(StringUtils::isNotBlank)
                                                .map(filename -> ContentDisposition.attachment().filename(mapFile.getFileName()).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));
            });
}

修改说明

  • 使用.defaultIfEmpty(null)给请求体Mono添加兜底值,当无请求体时会发出null而非空Mono,确保Mono.zip能获取到两个输入值并触发后续逻辑
  • 由于代码中并未实际使用请求体内容(已注释var dto = t.getT2()),传入null不会影响业务逻辑
  • 也可以用.switchIfEmpty(Mono.just(null))替代.defaultIfEmpty(null),效果完全一致

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:33:20