Web Worker 实现大文件分片加密上传的核心是将切片与加密移出主线程以避免卡顿,主线程负责调度、UI 和网络请求,Worker 专注本地切片与 AES-GCM 加密,数据通过 postMessage 安全流转,支持断点续传与错误重试。

用 Web Worker 实现大文件分片加密上传,核心是把「切片 + 加密」这两类耗时操作从主线程剥离,避免页面卡顿,同时保障安全性与可控性。关键不在“能不能做”,而在于“怎么分工合理、数据怎么安全流转、失败怎么兜住”。
主线程只管调度和通信
主线程负责用户交互、文件选择、上传控制和 UI 更新,不参与任何计算密集型任务:
- 监听
<input type="file">的 change 事件,拿到File对象 - 生成唯一标识(如
fileId = md5(fileName + fileSize))和随机 salt、IV(12 字节)等加密上下文 - 创建 Web Worker 实例(推荐使用模块化 worker:
new Worker('./uploader.worker.js', { type: 'module' })) - 用
postMessage()把文件对象(注意:需传file.slice()后的 Blob 或 ArrayBuffer)、分片参数(chunkSize=5MB)、加密元数据(salt、公钥 URL)一起发给 Worker - 监听 Worker 返回的进度、成功或错误消息,更新 UI 或触发重试逻辑
Worker 线程专注切片与本地加密
Worker 中执行真正吃 CPU 的操作,且全程不碰明文密钥:
- 接收主线程传入的
File,按字节偏移(start/end)循环调用file.slice()切出每一片(如 5MB) - 对每个分片:
- 生成独立 AES-GCM 密钥(
crypto.subtle.generateKey("AES-GCM", true, ["encrypt"])) - 用服务端下发的 RSA 公钥(提前加载并缓存)加密该 AES 密钥
- 用该 AES 密钥 + 唯一 IV 加密分片内容,提取 GCM
authTag - 将加密后分片(Uint8Array)、Base64 编码的
iv、encryptedKey、authTag打包为一个对象
- 生成独立 AES-GCM 密钥(
- 使用
Transferable(如[arrayBuffer])传递二进制数据,避免拷贝开销 - 每完成一片,立即
postMessage({ type: 'chunk-ready', data: ... })回主线程,不攒批
上传请求由主线程发起,带完整上下文
Worker 只产出加密载荷,不发网络请求——这是为了便于统一管理超时、重试、认证头和断点续传逻辑:
立即学习“前端免费学习笔记(深入)”;
- 主线程收到 Worker 发来的加密分片包后,构造 FormData:
formData.append('encryptedChunk', new Blob([data.encryptedBytes]))formData.append('iv', data.ivB64)formData.append('encryptedKey', data.encryptedKeyB64)formData.append('authTag', data.authTagB64)- 请求头带上
X-File-ID、X-Chunk-Index、X-Total-Chunks和防重放签名(如 HMAC-SHA256(fileId + index + timestamp)) - 用
fetch或XMLHttpRequest发送,控制并发数(建议 ≤3),配AbortController和 60s 超时
断点续传靠前后端协同校验
刷新页面不等于重头来过,关键在状态可恢复:
- 上传前,主线程先发
HEAD /upload/status?fileId=xxx查询已传成功的分片索引列表 - 对比本地待传分片序号,跳过已确认成功的项(服务端响应含
auth_tag_hash校验结果) - Worker 不保存状态,所有进度记录由主线程维护(可用
localStorage或IndexedDB存{ fileId, uploaded: [0,2,3] }) - 若某分片失败,仅重传该片:主线程重新调 Worker 加密同一片,再发请求
不复杂但容易忽略:Worker 中不能直接访问 localStorage 或 document;密钥不可序列化,必须在 Worker 内部生成或由主线程通过 importKey() 导入;所有 Web Crypto 操作必须在 HTTPS 下运行,否则 crypto.subtle 为空。



















