如何使用ReactJS将AWS S3存储桶的多个文件打包为ZIP批量下载
React 实现多个S3文件打包ZIP下载方案
1. 前置依赖安装
我们需要两个第三方库完成浏览器端打包+下载触发能力,执行以下命令安装:
npm install jszip file-saver
2. 核心实现逻辑
- 遍历你的文件数据结构,拿到每个文件的S3访问地址和文件名
- 通过fetch请求获取每个文件的Blob二进制数据(注意S3桶需要配置CORS允许你的前端域名访问,否则会跨域失败)
- 将所有Blob写入JSZip创建的压缩包实例中
- 所有文件添加完成后生成ZIP包的二进制流,触发浏览器下载
3. 完整代码示例
import { useState } from 'react'; import JSZip from 'jszip'; import { saveAs } from 'file-saver'; // 你的文件数据结构 const FILE_DATA = { item1: { name: "dummy.pdf", relativeUrl: "b9dde810-4935-4471-a22d-bdaf61e8bd62dummy.pdf", url: "https://upaged-file-store-prod.s3.ap-southeast-2.amazonaws.com/b9dde810-4935-4471-a22d-bdaf61e8bd62dummy.pdf?AWSAccessKeyId=AKIAVRO4YTL2YDUPVPPW&Expires=1625413917&Signature=z1DacLIOltfmFJbpt7AEy%2BeoK0s%3D" }, item2: { name: "Sell the Solution, Not the Product..png", relativeUrl: "6397c507-0d05-4cd7-8e4b-371249f72dbeSell the Solution, Not the Product..png", url: "https://upaged-file-store-prod.s3.ap-southeast-2.amazonaws.com/6397c507-0d05-4cd7-8e4b-371249f72dbeSell%20the%20Solution%2C%20Not%20the%20Product..png?AWSAccessKeyId=AKIAVRO4YTL2YDUPVPPW&Expires=1625413938&Signature=zkDHlWu9kv%2BXgOpRQToG%2Bpbyafk%3D" }, item3: { name: "ales-nesetril-Im7lZjxeLhg-unsplash.jpg", relativeUrl: "2e07b606-d1a0-4587-b8bb-c8f4b3927483ales-nesetril-Im7lZjxeLhg-unsplash.jpg", url: "https://upaged-file-store-prod.s3.ap-southeast-2.amazonaws.com/2e07b606-d1a0-4587-b8bb-c8f4b3927483ales-nesetril-Im7lZjxeLhg-unsplash.jpg?AWSAccessKeyId=AKIAVRO4YTL2YDUPVPPW&Expires=1625413971&Signature=U0d4%2BAPwi6e41c%2BU542ydoj%2BGBk%3D" }, item4: { name: "icons8-dashboard-layout-96.png", relativeUrl: "18b4312f-dd20-4c8f-89d3-bea024fb32b6icons8-dashboard-layout-96.png", url: "https://upaged-file-store-prod.s3.ap-southeast-2.amazonaws.com/18b4312f-dd20-4c8f-89d3-bea024fb32b6icons8-dashboard-layout-96.png?AWSAccessKeyId=AKIAVRO4YTL2YDUPVPPW&Expires=1625413996&Signature=9IXyDVvRKAAWcs2yR%2FChE4pj5Sc%3D" } }; const ZipDownloadButton = () => { const [loading, setLoading] = useState(false); const downloadZip = async () => { setLoading(true); const zip = new JSZip(); const fileList = Object.values(FILE_DATA); try { // 批量下载所有文件并写入zip const filePromises = fileList.map(async (file) => { const response = await fetch(file.url); if (!response.ok) throw new Error(`下载文件${file.name}失败`); const blob = await response.blob(); // 文件名如果有重复可以自行加前缀处理,避免zip内文件覆盖 zip.file(file.name, blob); }); // 等待所有文件下载完成 await Promise.all(filePromises); // 生成zip包 const zipBlob = await zip.generateAsync({ type: 'blob' }); // 触发下载 saveAs(zipBlob, '附件打包.zip'); } catch (err) { console.error('打包下载失败:', err); // 这里可以加你的错误提示逻辑,比如弹窗提示用户 } finally { setLoading(false); } }; return ( <button onClick={downloadZip} disabled={loading}> {loading ? '打包中...' : '下载全部附件'} </button> ); }; export default ZipDownloadButton;
4. 可选优化点
- 如果存在同名文件,写入zip时可以给文件名加随机后缀或者拼接ID,避免文件被覆盖
- 大文件打包时可以给JSZip的generateAsync方法添加进度回调,显示打包进度
- 如果文件数量过多或文件过大,建议改用后端打包方案,避免浏览器内存占用过高导致页面卡顿
内容的提问来源于stack exchange,提问作者Maria Andre
相关产品推荐
相关产品推荐

