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

Spring Boot WebFlux下AWS SDK v2的S3AsyncClient上传非空内容却生成0字节文件问题排查问询

Spring Boot WebFlux下AWS SDK v2的S3AsyncClient上传非空内容却生成0字节文件问题排查问询

我来帮你排查这个问题,结合你提供的代码和使用场景,可能的原因和对应的解决方案如下:

一、先排查异步上传是否存在隐藏异常

你的代码里把异步上传的CompletableFuture转成Mono后直接用then()忽略了返回值,很可能上传过程中出现了异常但没被捕获,导致S3只创建了空对象但没写入内容。建议你先给异步上传添加回调,打印异常信息:

修改S3AsyncUploadService的uploadFile方法:

public Mono<Void> uploadFile(String bucketName, String fileName, byte[] fileContent) {
    PutObjectRequest putObjectRequest = PutObjectRequest.builder()
        .bucket(bucketName)
        .key(fileName)
        .build();
    CompletableFuture<PutObjectResponse> uploadFuture = s3AsyncClient.putObject(
        putObjectRequest,
        AsyncRequestBody.fromBytes(fileContent)
    );
    // 添加回调排查异常
    uploadFuture.whenComplete((response, ex) -> {
        if (ex != null) {
            System.err.println("异步上传失败:" + ex.getMessage());
            ex.printStackTrace();
        } else {
            System.out.println("异步上传成功,ETag:" + response.eTag());
        }
    });
    return Mono.fromFuture(uploadFuture).then();
}

运行后查看控制台,如果有异常(比如HTTP客户端相关的错误),就能直接定位问题根源。

二、检查S3AsyncClient的依赖与配置

AWS SDK v2的S3AsyncClient依赖异步HTTP客户端实现(默认是Netty),如果你的项目里没有正确引入相关依赖,可能会导致上传逻辑异常:

如果是Maven项目,确保pom.xml里包含以下依赖:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
</dependency>
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>netty-nio-client</artifactId>
</dependency>

Gradle项目则添加:

implementation 'software.amazon.awssdk:s3'
implementation 'software.amazon.awssdk:netty-nio-client'

另外,确认你的S3AsyncClient是正确构建的,比如通过Spring自动配置或者手动构建:

@Bean
public S3AsyncClient s3AsyncClient() {
    return S3AsyncClient.builder()
        .region(Region.US_EAST_1) // 替换成你的实际区域
        .build();
}

如果客户端构建时缺少必要的配置,也可能导致内容无法正常传输。

三、手动指定Content-Length试试

虽然AsyncRequestBody.fromBytes()应该会自动处理内容长度,但某些场景下(比如SDK版本兼容问题),手动在PutObjectRequest里指定内容长度可以解决0字节问题:

修改S3AsyncUploadService里的请求构建代码:

PutObjectRequest putObjectRequest = PutObjectRequest.builder()
    .bucket(bucketName)
    .key(fileName)
    .contentLength((long) fileContent.length) // 手动设置内容长度
    .build();

这样可以明确告诉S3要接收的字节数,避免因自动长度识别失败导致的空文件。

四、检查AWS SDK v2版本

如果你的SDK版本较旧,可能存在AsyncRequestBody的已知bug。建议升级到最新的稳定版本,比如在Maven中指定:

<properties>
    <aws.sdk.version>2.25.0</aws.sdk.version> <!-- 替换成最新稳定版 -->
</properties>
<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
        <version>${aws.sdk.version}</version>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

五、验证WebFlux线程模型的影响

WebFlux使用非阻塞线程池,虽然AsyncRequestBody.fromBytes()是线程安全的,但可以尝试用Mono.fromCallable包装异步上传逻辑,确保上下文正确:

public Mono<Void> uploadFile(String bucketName, String fileName, byte[] fileContent) {
    return Mono.fromCallable(() -> {
        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
            .bucket(bucketName)
            .key(fileName)
            .build();
        return s3AsyncClient.putObject(
            putObjectRequest,
            AsyncRequestBody.fromBytes(fileContent)
        );
    }).flatMap(future -> Mono.fromFuture(future)).then();
}

不过这个方案的优先级低于前面几个,因为你的同步上传正常,说明byte[]本身是没问题的。

建议先从第一步排查异常开始,这是最容易定位问题的方法。如果发现异常信息,再针对性解决。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:47:57