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

如何通过预签名URL将S3文件转存至另一存储桶(Java Spring Boot)

实现S3预签名URL直接转存到目标S3存储桶(Spring Boot方案)

核心思路

S3本身不支持通过第三方预签名URL直接跨桶复制,所以我们需要在Spring Boot应用中做中转:通过预签名URL获取源文件的输入流,直接将流上传到目标S3桶,全程不落地本地文件,避免额外的磁盘IO开销。

步骤1:引入依赖

如果使用AWS SDK v2(推荐版本),在pom.xml中添加以下依赖:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.20.100</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

步骤2:配置S3客户端

创建配置类初始化用于操作目标存储桶的S3客户端:

import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class S3Config {

    @Bean
    public S3Client s3Client() {
        // 替换为目标存储桶所在的AWS区域
        Region region = Region.US_EAST_1;
        return S3Client.builder()
                .region(region)
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();
    }
}

注意:确保应用运行环境拥有访问目标S3桶的权限(比如通过IAM角色、环境变量配置的密钥等方式)。

步骤3:实现转存服务

编写核心转存逻辑,直接通过流传递数据,避免本地存储:

import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

@Service
public class S3TransferService {

    private final S3Client s3Client;

    public S3TransferService(S3Client s3Client) {
        this.s3Client = s3Client;
    }

    public void transferViaPresignedUrl(String sourcePresignedUrl, String targetBucket, String targetKey) throws Exception {
        // 1. 通过预签名URL获取源文件输入流
        URL url = new URL(sourcePresignedUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        
        try (InputStream inputStream = connection.getInputStream()) {
            // 2. 直接将流上传到目标S3桶
            PutObjectRequest putRequest = PutObjectRequest.builder()
                    .bucket(targetBucket)
                    .key(targetKey)
                    .build();
            
            s3Client.putObject(putRequest, software.amazon.awssdk.core.sync.RequestBody.fromInputStream(inputStream, connection.getContentLengthLong()));
        } finally {
            connection.disconnect();
        }
    }
}

步骤4:接口调用示例

如果需要对外提供转存接口,可以编写一个简单的Controller:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TransferController {

    private final S3TransferService transferService;

    public TransferController(S3TransferService transferService) {
        this.transferService = transferService;
    }

    @PostMapping("/transfer-s3")
    public ResponseEntity<String> transferFile(
            @RequestParam String sourcePresignedUrl,
            @RequestParam String targetBucket,
            @RequestParam String targetKey) {
        try {
            transferService.transferViaPresignedUrl(sourcePresignedUrl, targetBucket, targetKey);
            return ResponseEntity.ok("文件转存成功");
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("转存失败:" + e.getMessage());
        }
    }
}

关键注意事项

  • 预签名URL权限:确保源桶的预签名URL拥有GET权限,且未超过有效期。
  • 流资源管理:必须使用try-with-resources语法自动关闭输入流,避免资源泄漏。
  • 异常细化处理:生产环境中需针对连接超时、S3权限不足、预签名URL无效等场景单独捕获处理。
  • 大文件优化:如果处理超大文件,建议使用S3的分段上传(Multipart Upload)功能,避免内存溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:32:57