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

如何在AWS SDK JS v3中实现S3多图片批量上传?

多文件批量上传改造实现

你现有单图上传逻辑可以直接复用,只需要做三处调整即可支持多文件批量上传,不需要额外引入依赖。

1. 调整状态与文件选择控件

原来的单文件状态只能存一个File对象,先替换为数组状态存储多文件,同时给文件选择框加multiple属性支持多选:

// 替换原单文件状态
const [fileList, setFileList] = useState<File[]>([]);

// 文件选择控件新增multiple属性,可加accept限制仅选图片
<input 
  type="file" 
  id="file" 
  multiple 
  accept="image/*" 
  onChange={fileChange} 
/>

对应的文件选择回调也要同步修改,把选中的文件列表转成数组存入状态:

const fileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const selectedFiles = Array.from(e.target.files || []);
  setFileList(selectedFiles);
};

2. 改造上传逻辑

你之前写的mediaData FormData拼装是后端中转上传的写法,直连S3的场景不需要这部分,直接遍历选中的文件,为每个文件生成独立的S3上传任务即可。
注意S3客户端和凭证只需要初始化一次,不要每个文件重复创建:

const handleUpload = async () => {
  if (!fileList.length) {
    console.warn('请先选择需要上传的文件');
    return;
  }

  // 统一初始化S3客户端与凭证
  const creds = {
    accessKeyId: process.env.REACT_APP_HOST_AWS_ACCESS_KEY_ID || '',
    secretAccessKey: process.env.REACT_APP_HOST_AWS_SECRET_ACCESS_KEY || '',
  };
  const s3Client = new S3Client({
    region: process.env.REACT_APP_HOST_AWS_DEFAULT_REGION || '',
    credentials: creds,
  });

  // 总进度统计
  const totalFileSize = fileList.reduce((sum, file) => sum + file.size, 0);
  const progressMap = new Map<string, number>();

  // 为每个文件生成上传任务
  const uploadTasks = fileList.map((file) => {
    // 生成唯一存储路径,加时间戳避免同名文件覆盖
    const storageKey = `events/${eventDetails.id}/${Date.now()}_${file.name}`;
    const uploadParams = {
      Bucket: process.env.REACT_APP_HOST_AWS_BUCKET,
      Key: storageKey,
      Body: file,
      // 动态读取文件类型,不要写死image/jpg,否则png/webp等格式会异常
      ContentType: file.type || 'image/jpeg',
    };

    const uploader = new Upload({
      client: s3Client,
      leavePartsOnError: false,
      params: uploadParams,
    });

    // 单文件进度汇总为总进度
    uploader.on('httpUploadProgress', (progress) => {
      progressMap.set(storageKey, progress.loaded || 0);
      const totalLoaded = Array.from(progressMap.values()).reduce((sum, cur) => sum + cur, 0);
      console.log(`上传进度:${Math.round((totalLoaded / totalFileSize) * 100)}%`);
    });

    // 返回上传Promise,完成后返回文件信息
    return uploader.done().then((res) => ({
      originName: file.name,
      storageKey,
      fileUrl: res.Location,
    }));
  });

  try {
    // 并行执行所有上传任务,等待全部完成
    const allUploadedFiles = await Promise.all(uploadTasks);
    console.log('全部文件上传完成', allUploadedFiles);
    // 后续可将allUploadedFiles提交到业务后端存储关联关系
  } catch (err) {
    console.error('上传失败', err);
  }
};

注意事项

  • 如果你后续需要改成后端中转上传(不直连S3),直接把之前拼好的mediaData通过POST请求发给后端接口即可,不需要前端初始化S3客户端
  • 如果单次要传的大文件数量较多,可以加并发控制(比如同时最多传3个文件),避免一次性发起太多请求导致浏览器卡顿
  • 存储路径建议加随机串/时间戳前缀,避免不同用户上传同名文件导致资源覆盖
  • 不要硬编码ContentType为image/jpg,优先读取文件自带的MIME类型,否则会导致非jpg格式的图片上传后无法正常预览

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 09:06:52