You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在不共享密钥的情况下实现AWS S3分片上传?

解决S3大图片上传的Node.js实用方案

嘿,我刚好处理过类似的S3大文件上传场景,针对你遇到的「预签名URL不能分片」(其实是可以的!)、API Gateway/Lambda负载限制的问题,给你几个落地可行的方案:

方案1:用S3预签名URL实现分片上传

你之前可能对预签名URL的能力有误解——S3的预签名URL完全支持分片上传流程,这也是处理大文件最推荐的方案,直接绕开API Gateway和Lambda的负载限制,性能拉满。

具体流程很清晰:

  • 你的Node.js后端调用createMultipartUpload初始化分片上传,拿到唯一的UploadId
  • 根据图片大小拆分分片(S3要求每个分片至少5MB,最后一个分片可以更小,建议按5-10MB拆分)
  • 为每个分片生成独立的预签名URL,把这些URL和UploadId一起返回给移动端
  • 移动端并行上传所有分片到对应的预签名URL(直接和S3通信,不经过你的后端)
  • 所有分片上传完成后,移动端通知后端调用completeMultipartUpload收尾,完成整个上传

给你一段Node.js的核心代码示例(用AWS SDK v3,现在官方推荐的版本):

import { S3Client, CreateMultipartUploadCommand, PutObjectCommand, CompleteMultipartUploadCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3Client = new S3Client({ region: "你的AWS区域" });

// 初始化分片上传
export async function initMultipartUpload(bucketName, objectKey, contentType) {
  const command = new CreateMultipartUploadCommand({
    Bucket: bucketName,
    Key: objectKey,
    ContentType: contentType // 比如image/jpeg、image/png
  });
  const response = await s3Client.send(command);
  return { uploadId: response.UploadId, key: response.Key };
}

// 生成单个分片的预签名上传URL
export async function generatePresignedPartUrl(bucketName, objectKey, uploadId, partNumber) {
  const command = new PutObjectCommand({
    Bucket: bucketName,
    Key: objectKey,
    UploadId: uploadId,
    PartNumber: partNumber
  });
  // 设置URL有效期,比如1小时,足够用户完成上传
  const url = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
  return url;
}

// 完成分片上传
export async function finishMultipartUpload(bucketName, objectKey, uploadId, uploadedParts) {
  // uploadedParts是移动端返回的每个分片的ETag和PartNumber
  const command = new CompleteMultipartUploadCommand({
    Bucket: bucketName,
    Key: objectKey,
    UploadId: uploadId,
    MultipartUpload: { Parts: uploadedParts }
  });
  await s3Client.send(command);
}

这个方案完全不需要API Gateway参与,所有上传流量直接走S3,既解决了大小限制问题,又能支撑大量并发上传。

方案2:用AWS Amplify Storage省掉重复造轮子

如果不想自己写分片上传的底层逻辑,AWS Amplify的Storage模块已经封装好了S3分片上传、断点续传、权限控制等功能,不管是Node.js后端还是移动端,都能快速集成。

Node.js后端的配置示例:

import { Amplify } from 'aws-amplify';
import { Storage } from 'aws-amplify/storage';

Amplify.configure({
  Auth: {
    // 配置你的AWS Cognito或者自定义认证方式
    identityPoolId: '你的身份池ID',
    region: '你的AWS区域'
  },
  Storage: {
    AWSS3: {
      bucket: '你的S3桶名',
      region: '你的AWS区域'
    }
  }
});

// 如果你需要后端控制上传权限,可以生成带策略的上传凭证
export async function getUploadAuthorization(objectKey) {
  const uploadConfig = await Storage.configure(objectKey, { 
    level: 'public', // 或者private,根据业务需求
    contentType: 'image/jpeg'
  });
  return uploadConfig;
}

移动端直接调用Amplify的Storage.put方法,它会自动处理分片拆分、并行上传、失败重试,你完全不用关心底层细节,适合快速迭代的项目。

方案3:开启S3 Transfer Acceleration加速全球上传

如果你的用户分布在全球各地,可以开启S3 Transfer Acceleration,结合分片上传进一步提升上传速度。只需要在初始化S3客户端时指定加速端点即可:

const s3Client = new S3Client({
  region: "你的AWS区域",
  endpoint: `https://${bucketName}.s3-accelerate.amazonaws.com`
});

这样生成的预签名URL会指向S3的全球加速节点,减少跨地域上传的延迟,用户体验会更好。


总结一下,预签名URL分片上传是最适合你的场景的方案,既解决了API Gateway和Lambda的大小限制,又能高效处理大量图片上传;如果想省时间,Amplify Storage是绝佳的偷懒选择。

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

火山引擎 最新活动