使用Java AWS Lambda将S3文件下载至本地的实现方案
可行方案说明
Lambda是无服务器执行环境,无法直接主动将文件传输到你的本地电脑,需要通过间接中转的方式实现,以下是两种实用方案:
方案1:通过API Gateway返回文件内容,本地发起HTTP请求下载
修改Lambda代码,将/tmp目录下的文件读取为字节流,通过API Gateway返回给本地客户端:
- 调整Lambda的返回类型,适配API Gateway的响应格式
- 在API Gateway控制台配置支持对应文件的二进制媒体类型(如
application/pdf、image/jpeg等) - 本地用curl、Postman或自定义脚本发起请求,将响应内容保存为本地文件
修改后的核心代码示例:
import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; import software.amazon.awssdk.services.s3.transfer.S3TransferManager; import software.amazon.awssdk.services.s3.transfer.DownloadFileRequest; import software.amazon.awssdk.services.s3.transfer.FileDownload; import software.amazon.awssdk.services.s3.transfer.CompletedFileDownload; import software.amazon.awssdk.transfer.s3.LoggingTransferListener; public class S3DownloadHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { @Override public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) { String bucketName = "your-target-bucket"; String key = "your-file-key"; String downloadedFileWithPath = "/tmp/downloaded-file"; // 原有下载到/tmp的逻辑 S3TransferManager transferManager = S3TransferManager.create(); DownloadFileRequest downloadFileRequest = DownloadFileRequest.builder() .getObjectRequest(b -> b.bucket(bucketName).key(key)) .addTransferListener(LoggingTransferListener.create()) .destination(Paths.get(downloadedFileWithPath)) .build(); FileDownload downloadFile = transferManager.downloadFile(downloadFileRequest); CompletedFileDownload downloadResult = downloadFile.completionFuture().join(); // 读取文件并构造API响应 APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); try { byte[] fileBytes = Files.readAllBytes(Paths.get(downloadedFileWithPath)); response.setStatusCode(200); response.setIsBase64Encoded(true); response.setBody(Base64.getEncoder().encodeToString(fileBytes)); // 设置文件类型和下载文件名 response.getHeaders().put("Content-Type", "application/octet-stream"); response.getHeaders().put("Content-Disposition", "attachment; filename=\"local-saved-file\""); } catch (Exception e) { response.setStatusCode(500); response.setBody("文件读取失败: " + e.getMessage()); } return response; } }
本地下载命令示例(curl):
curl -X GET "https://your-api-gateway-endpoint/your-path" -o local-file-name
方案2:生成S3预签名URL,本地通过URL下载
如果文件较大(超过API Gateway默认10MB限制),优先用此方案:
- 将/tmp中的文件上传到一个临时S3位置(可复用原桶或单独的临时桶)
- 生成该文件的预签名URL(自定义有效期,比如1小时)
- Lambda返回这个URL,本地通过浏览器或curl访问URL完成下载
核心代码示例:
// 原有下载到/tmp的逻辑省略... // 上传/tmp文件到临时S3路径 String tempBucket = "your-temp-bucket"; String tempKey = "temp/downloads/" + System.currentTimeMillis() + "-file"; UploadFileRequest uploadRequest = UploadFileRequest.builder() .putObjectRequest(b -> b.bucket(tempBucket).key(tempKey)) .source(Paths.get(downloadedFileWithPath)) .build(); CompletedFileUpload uploadResult = transferManager.uploadFile(uploadRequest).completionFuture().join(); // 生成1小时有效期的预签名URL GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(tempBucket) .key(tempKey) .build(); PresignedGetObjectRequest presignedRequest = transferManager.presignGetObject(getObjectRequest, Duration.ofHours(1)); // 返回预签名URL(适配API Gateway的话直接返回字符串即可) return presignedRequest.url().toString();
本地下载命令示例:
curl -X GET "https://your-temp-bucket.s3.your-region.amazonaws.com/temp/downloads/123456789-file" -o local-file-name
注意事项
- Lambda的/tmp目录默认最大存储512MB,超大文件无法下载到该目录
- 预签名URL的有效期不要设置过长,避免未授权访问风险
- 若用方案1,需确保API Gateway的payload限制能覆盖文件大小
内容的提问来源于stack exchange,提问作者Vikram
相关产品推荐
相关产品推荐

