是否可暂停恢复AWS S3存储桶对象下载?aws-sdk-js是否支持该功能?
AWS S3 下载暂停/恢复功能实现方案(Electron + aws-sdk-js 环境)
原生支持情况
aws-sdk-js(v2、v3 版本均支持)原生具备实现暂停、恢复下载的能力,不需要额外引入第三方依赖,核心依赖 S3 服务本身支持的 HTTP Range 范围请求特性。
实现逻辑
原理非常简单:
- 暂停:中断当前正在执行的下载请求,本地持久化记录当前已下载的字节偏移量、S3 对象的 ETag(用于校验对象是否变更)、本地文件路径
- 恢复:读取本地记录的偏移量,调用 S3 接口时指定
Range请求头,从偏移量位置开始下载剩余内容,追加写入本地文件即可
代码实现示例(aws-sdk-js v3,Electron 主进程环境可用)
1. 状态存储定义
你可以把该状态持久化到 Electron 本地存储、配置文件中,应用重启后依然可以恢复下载:
const { S3Client, HeadObjectCommand, GetObjectCommand } = require("@aws-sdk/client-s3"); const fs = require("node:fs"); const path = require("node:path"); const s3Client = new S3Client({ region: "你的S3桶所在区域", // 你的AWS认证配置 }); // 下载状态,可根据实际需求持久化 const downloadState = { bucket: "目标桶名", key: "S3对象的Key", localSavePath: path.join(__dirname, "下载的文件保存路径"), downloadedBytes: 0, totalBytes: 0, eTag: "", isPaused: false, currentDownloadTask: null, };
2. 下载/恢复逻辑
async function runDownload() { // 先获取对象元信息,校验对象是否变更 const headResp = await s3Client.send( new HeadObjectCommand({ Bucket: downloadState.bucket, Key: downloadState.key, }) ); // 如果本地已记录ETag,和最新的ETag对比,不一致说明对象已修改,需要重新下载 if (downloadState.eTag && downloadState.eTag !== headResp.ETag) { downloadState.downloadedBytes = 0; if (fs.existsSync(downloadState.localSavePath)) { fs.unlinkSync(downloadState.localSavePath); } } downloadState.totalBytes = headResp.ContentLength; downloadState.eTag = headResp.ETag; // 读取本地已下载的文件大小 if (fs.existsSync(downloadState.localSavePath)) { const fileStats = fs.statSync(downloadState.localSavePath); downloadState.downloadedBytes = fileStats.size; } // 已下载完成直接返回 if (downloadState.downloadedBytes >= downloadState.totalBytes) { console.log("文件已下载完成"); return; } // 构造范围下载请求 const getObjectCmd = new GetObjectCommand({ Bucket: downloadState.bucket, Key: downloadState.key, Range: `bytes=${downloadState.downloadedBytes}-`, }); downloadState.isPaused = false; downloadState.currentDownloadTask = s3Client.send(getObjectCmd); const downloadResp = await downloadState.currentDownloadTask; // 追加写入本地文件 const writeStream = fs.createWriteStream(downloadState.localSavePath, { flags: "a" }); const reader = downloadResp.Body.getReader(); while (true) { // 检测到暂停标记,终止下载流程 if (downloadState.isPaused) { await reader.cancel(); writeStream.close(); return; } const { done, value } = await reader.read(); if (done) break; writeStream.write(value); downloadState.downloadedBytes += value.length; // 这里可以自行添加下载进度回调逻辑 } writeStream.close(); console.log("文件下载完成"); }
3. 暂停逻辑
function pauseDownload() { downloadState.isPaused = true; // 也可以直接中断请求:downloadState.currentDownloadTask.abort() }
额外优化建议
- 对于超过10GB的大文件,建议拆分为多个10MB~100MB大小的分段并行下载,暂停时记录每个分段的下载状态,恢复时只下载未完成的分段,下载速度更快
- Electron 渲染进程调用的话,可以通过预加载脚本把下载、暂停方法暴露给渲染层,避免把AWS认证信息暴露到渲染进程
- 下载过程中建议定时持久化
downloadState状态,避免应用异常退出导致下载进度丢失
内容的提问来源于stack exchange,提问作者leo
相关产品推荐
相关产品推荐

