AWS S3·CloudFront 文件上传限制汇总|分块上传·预签名 URL
使用 AWS 构建文件上传功能时,S3、CloudFront、API Gateway 和 Lambda 各自都有不同的大小限制。理解哪一层可能成为瓶颈非常重要。本文整理了各服务的限制值,解释了用于处理大文件的分块上传和预签名 URL 的使用方法,以及 PHP 实现示例。
Amazon S3 上传限制
上传对象到 S3 的大小限制因方法而异。
| 上传方式 | 最大大小 | 备注 |
|---|---|---|
| PUT Object(单个) | 5 GB | 每个请求的上传限制 |
| Multipart Upload | 5 TB | 单个对象的最大大小 |
| 每个部分 | 最小 5 MB ~ 最大 5 GB | 仅最后一个部分可以小于 5 MB |
| 部分数量 | 最多 10,000 个部分 | 分段上传时的上限 |
AWS 建议对 100 MB 以上的文件使用分块上传。从网络故障时的重传效率和并行传输提升吞吐量的角度来看,应该积极地用于大文件。
需要分段上传的情况
分段上传是一种方法,将一个对象分成多个部分,分别以独立的请求发送,最后进行合并。在以下情况下很有效。
- <strong>100 MB 或更大的文件</strong>:这是 AWS 推荐的分段上传阈值。
- <strong>网络不稳定的环境</strong>:即使在传输中途出错,也只需重新发送失败的分块。
- <strong>最大化吞吐量</strong>:并行上传多个分块可提高传输速度。
- <strong>上传暂停·恢复</strong>:保存 Upload ID 可以跨会话恢复。
分段上传流程大致分为3个步骤。
- <strong>启动</strong>(CreateMultipartUpload):获取上传 ID
- <strong>发送分块</strong>(UploadPart):上传每个分块并记录 ETag
- <strong>完成</strong>(CompleteMultipartUpload):发送部分号和 ETag 列表以确定对象
如果取消上传而不调用 <code>AbortMultipartUpload</code>,未完成的分段将继续作为存储费用被收费。强烈建议在S3存储桶的生命周期策略中设置"删除N天后未完成的多部分上传"。
预签名 URL 的有效期和大小
使用带签名的 URL (Presigned URL),没有 S3 访问权限的客户端(如浏览器或移动应用)可以直接将文件上传到 S3。由于服务器不充当中介,大文件也可以高效处理。
| 项目 | 限制与规格 |
|---|---|
| 最大有效期(IAM 用户颁发) | 7天(604,800秒) |
| 最大有效期(IAM 角色颁发) | 在角色的会话时间内(最长12小时) |
| 最大可上传文件大小 | 单一PUT最多5GB |
| 多部分支持 | 为每个部分发行单独的 Presigned URL |
预签名 URL 在后端生成并返回给客户端,客户端然后向该 URL 直接发送 PUT 请求。由于 URL 包含签名,它仅在有效期内上载正确文件时成功。
CloudFront的body大小限制
当通过CloudFront将请求转发到源服务器(如S3或EC2等)时,请求正文的大小受到限制。
| 设置 | 默认值 | 最大值 |
|---|---|---|
| 请求正文大小(默认) | 1 MB | 可在分发设置中更改 |
| 通过 Lambda@Edge 的情况 | 1 MB | 1 MB(不可更改) |
| 在CloudFront Functions的情况下 | — | 无法访问请求正文 |
在CloudFront分配设置中,您可以启用「Allow requests with body」并提高限制,但请注意Lambda@Edge的1 MB限制无法更改。对于上传大型文件,建议采用绕过CloudFront的架构,使用Presigned URL直接从客户端上传到S3。
API Gateway 的有效负载限制
API Gateway(REST API 和 HTTP API)都有有效负载大小限制。
| API 类型 | 最大负载大小 | 备注 |
|---|---|---|
| REST API | 10 MB | 启用二进制支持时也是如此 |
| HTTP API | 10 MB | — |
| WebSocket API | 128 KB(消息)/ 32 KB(帧) | — |
API Gateway 的 10 MB 限制被归类为 AWS 服务配额,无法增加。通过 API Gateway 上传超过 10 MB 的文件被认为是设计缺陷;请考虑迁移到预签名 URL 模式。
通过 Lambda 的文件限制
在 Lambda 函数中接收文件时,API Gateway 传递的事件有效负载有大小限制。此外,Lambda 本身还具有以下约束。
| 限制项目 | 值 |
|---|---|
| 同步调用(Request)有效负载 | 6 MB |
| 同步调用(Response)有效负载 | 6 MB |
| 异步调用有效负载 | 256 KB |
| <code>/tmp</code> 目录的存储容量 | 默认 512 MB(最大 10 GB) |
| 最大执行时间 | 15分钟 |
在 Lambda 中处理文件时,临时文件会写入 <code>/tmp</code>。默认值为 512 MB,但可以通过 Lambda 配置将临时存储扩展至最大 10 GB(需要额外费用)。
PHP中S3多部分上传代码示例
这是使用 AWS SDK for PHP(v3)实现分块上传的示例。使用 SDK 的 <code>MultipartUploader</code> 类可以自动处理分块、重试和完成处理。
use Aws\S3\S3Client;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;
$s3 = new S3Client([
'region' => 'ap-northeast-1',
'version' => 'latest',
]);
$uploader = new MultipartUploader($s3, '/path/to/large-file.mp4', [
'bucket' => 'your-bucket-name',
'key' => 'uploads/' . basename('/path/to/large-file.mp4'),
'before_initiate' => function (\Aws\Command $command) {
// アップロード開始前のフック
},
'before_upload' => function (\Aws\Command $command) {
// 各パートアップロード前のフック(プログレス表示など)
},
'concurrency' => 5, // 並列アップロード数
'part_size' => 10 * 1024 * 1024, // 1パート = 10 MiB
]);
try {
$result = $uploader->upload();
echo 'アップロード完了: ' . $result['ObjectURL'];
} catch (MultipartUploadException $e) {
// 失敗したパートから再開する例
$uploader = new MultipartUploader($s3, '/path/to/large-file.mp4', [
'state' => $e->getState(),
]);
$result = $uploader->upload();
}
以下是如何发行预签名 URL 并允许客户端直接上传到 S3 的方法。
use Aws\S3\S3Client;
$s3 = new S3Client([
'region' => 'ap-northeast-1',
'version' => 'latest',
]);
// 署名付きURLを生成(有効期限: 15分)
$cmd = $s3->getCommand('PutObject', [
'Bucket' => 'your-bucket-name',
'Key' => 'uploads/' . uniqid('', true) . '.jpg',
'ContentType' => 'image/jpeg',
]);
$request = $s3->createPresignedRequest($cmd, '+15 minutes');
$presignedUrl = (string) $request->getUri();
// このURLをクライアントに返す
// クライアントはこのURLに PUT リクエストでファイルを直接送信する
echo json_encode(['upload_url' => $presignedUrl]);
架构选择指南
- <strong>~10 MB</strong>:可通过 API Gateway → Lambda → S3 简单实现
- <strong>10 MB–100 MB</strong>:建议使用预签署 URL 直接从客户端上传到 S3
- <strong>100 MB~5 GB</strong>:使用 Presigned URL + 分块上传实现稳定传输
- <strong>超过 5 GB</strong>:必须使用分块上传(单独 PUT 不可行)
使用 DevLab 阈值文件的测试步骤
要实际验证 <code>S3</code> 上传设置,您需要精确大小的测试文件。使用 DevLab 的边界值测试文件,您可以高效地验证特定大小前后的行为。
- 从 DevLab 的 <a href="/ja/files/threshold/">边界值测试文件列表</a> 中下载所需大小的文件。
- 验证分段切换阈值时,也可以利用 <a href="/ja/files/images/png/">PNG 测试图像</a>的大尺寸版本。
- 使用 <code>aws s3 cp</code> 命令或 SDK 的 <code>PutObject</code> / <code>MultipartUploader</code> 上传下载的文件,并验证大小限制前后文件的成功或失败情况。
本文中可用的测试文件
- <a href="/ja/files/threshold/" class="text-primary-600 dark:text-primary-400 hover:underline">边界值测试文件列表</a> — 用于验证 S3、API Gateway、Lambda 各上限
- <a href="/ja/files/threshold/10mb/" class="text-primary-600 dark:text-primary-400 hover:underline">10MB 边界值测试集合</a> — 确认 API Gateway 10MB 上限的直前·直后
- <a href="/ja/files/threshold/25mb/" class="text-primary-600 dark:text-primary-400 hover:underline">25MB 边界值测试集</a> — 用于验证多部分推荐线前后的行为
- <a href="/ja/files/images/png/" class="text-primary-600 dark:text-primary-400 hover:underline">PNG 测试图像列表</a> — 用于验证图像上传管道功能
相关文章
- <a href="/ja/blog/how-to-test-upload-limit/" class="text-primary-600 dark:text-primary-400 hover:underline">如何正确测试文件上传大小限制</a>
- <a href="/ja/blog/php-file-upload/" class="text-primary-600 dark:text-primary-400 hover:underline">PHP 文件上传实现方法|验证·存储·安全完全指南</a>
- <a href="/ja/blog/multipart-form-data-overhead/" class="text-primary-600 dark:text-primary-400 hover:underline">准确计算 multipart/form-data 开销</a>
- <a href="/ja/blog/mb-vs-mib-file-size/" class="text-primary-600 dark:text-primary-400 hover:underline">MB和MiB不一样!文件大小单位的陷阱</a>