根本原因是JSZip.loadAsync()不接受File对象,只支持ArrayBuffer、Blob或Uint8Array;正确做法是用file.arrayBuffer()转换后再传入,否则报“Invalid or corrupted zip”错误。

按钮点击后解压 ZIP 文件,为什么 JSZip 一直报错?
根本原因不是 ZIP 文件损坏,而是 JSZip.loadAsync() 拒绝接收 File 对象——哪怕它看起来“就是个文件”。浏览器里 File 是 Blob 的子类,但 JSZip 内部校验严格,只认 ArrayBuffer、Blob 或 Uint8Array。
- 错误写法:
JSZip.loadAsync(file)→ 控制台报Uncaught (in promise) Error: Invalid or corrupted zip - 正确写法:
JSZip.loadAsync(await file.arrayBuffer()) - 若 ZIP 来自
fetch(),确保响应头含Content-Type: application/zip,否则response.blob()可能被误判为text/plain - 别用已废弃的
JSZipUtils.getBinaryContent(),它在 CORS 场景下必然失败
解压出来的图片为什么显示为黑块或 404?
JSZip 解压出的是原始二进制数据,不能直接塞进 <img src>。你看到的黑块,是浏览器试图把二进制当文本解析的结果。
- 错误写法:
img.src = 'data:image/png;base64,' + base64Str—— JSZip 不提供现成 base64,且大图 base64 会阻塞渲染 - 正确顺序:
const blob = await zip.file('img/logo.png').async('blob');→const url = URL.createObjectURL(blob);→img.src = url; - 必须在页面卸载前调用
URL.revokeObjectURL(url),否则内存泄漏 - 对非图片文件(如 JSON、TXT),可用
.async('text')或.async('uint8array')获取对应格式
大 ZIP 文件(>50MB)点一下就卡死?
JSZip 在主线程全量加载并解压,遇到大文件极易触发浏览器内存限制或 UI 冻结。这不是你代码写错了,是 JSZip 架构决定的。
- 换用
zip.js(@zip.js/zip.js),它默认启用 Web Worker 和流式读取 - 初始化时显式指定
workerUrl:new zip.ZipReader(new zip.BlobReader(file), { workerUrl: 'https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.28/worker.js' }) - 先调用
readEntries()获取目录结构,再按需解压单个文件,避免unzipAll()一次性加载全部内容 - 若 ZIP 含密码,
zip.js原生支持;JSZip不支持,硬加 crypto 模块也不推荐
ZIP 里藏了 ../../../etc/passwd 怎么办?
JSZip 默认不做路径校验,恶意 ZIP 可通过相对路径逃逸,解压到任意位置(虽然浏览器沙箱限制实际写入,但路径遍历本身已是风险信号)。
立即学习“前端免费学习笔记(深入)”;
- 解压前必须校验每个文件路径:用正则或
path.posix.normalize()判断是否以'..'开头或含'../' - 拒绝解压任何含非法路径的条目,或统一重写为安全前缀(如
safe_extract/) - 即使只读取内容不落地,也要清理路径——这是容易被忽略的合规红线



















