file.slice() 参数必须为字节偏移量,非字符数或mb字符串;正确写法是显式换算如510241024,并用math.min兜底防越界;需兼容旧浏览器前缀、限流并发、携带content-range、用文件哈希生成uploadid实现断点续传,优先选用xmlhttprequest而非fetch。

File.slice() 的参数必须是字节偏移量,不是字符数或 MB 字符串
很多人写 file.slice(0, '2MB') 或 file.slice(0, 2000000),结果上传后文件损坏、服务端校验哈希失败、Content-Range 报 Invalid range。因为 File 是二进制 Blob,slice() 的 start 和 end 单位永远是字节(byte),不是字符、行、也不是带单位的字符串。
正确写法是显式换算:file.slice(0, 5 * 1024 * 1024) 表示前 5MB;用 Math.min(start + chunkSize, file.size) 做边界兜底,避免越界。
- 别依赖肉眼估算——UTF-8 中一个中文字符占 1–3 字节,
slice(0, 100)可能只切了几十个汉字 - 不要硬编码数值如
5242880,可读性差且易错;统一用5 * 1024 * 1024或定义常量const CHUNK_SIZE = 5 * 1024 * 1024 - 旧浏览器需兼容前缀:
file.webkitSlice?.(start, end)或file.mozSlice?.(start, end),现代浏览器已原生支持slice
并发上传必须限流,不能直接 Promise.all(fileChunks)
把 1GB 文件切成 200 个 5MB 分片,然后 Promise.all(chunks.map(upload)) 会瞬间发出 200 个请求——触发 Chrome 同域最大 6 连接限制、服务端限流拒绝、内存暴涨甚至页面卡死。
稳定做法是控制“飞行中”请求数 ≤ 4,推荐用 Promise.allSettled + 固定长度队列,每次只提交最多 4 个分片:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 每个
XMLHttpRequest实例必须独立创建,不能复用;上传完成立即设xhr = null释放引用 - 每个请求头必须带
Content-Range: bytes 0-5242879/1073741824,服务端靠它定位位置 - 避免在主线程同步计算大文件哈希(如 MD5),会阻塞 UI;要用
Web Worker或流式crypto.subtle.digest
断点续传不能只靠文件名,必须用文件指纹做 uploadId
用户重选同名文件、或同一文件修改后再次上传,仅靠 file.name 无法区分。服务端若按名查进度,会误判“已传完”或覆盖旧状态。
可靠方案是前端生成文件唯一 ID:
- 用
crypto.subtle.digest('SHA-256', buffer)计算整个文件哈希(分块读 + 流式 digest 避免内存爆) - 将该哈希作为
uploadId发起预检请求,服务端返回已上传的chunkIndex列表 - 前端跳过这些索引,只上传剩余分片;刷新后从
localStorage读取uploadId和已传索引继续 - 每个分片请求额外携带
chunkIndex、totalChunks、chunkHash(可选),服务端用于去重和校验
fetch 和 XMLHttpRequest 在分片上传中的关键差异
两者都能发请求,但实际行为影响稳定性:
-
fetch默认不支持上传进度监听,需手动包装Blob为ReadableStream+TransformStream,复杂且兼容性差;XMLHttpRequest.upload.onprogress开箱即用 -
XMLHttpRequest.abort()终止可靠;fetch的AbortController对已发出请求的中止效果依赖浏览器实现,部分旧版可能无效 - 若服务端要求自定义 header(如
X-Upload-Chunk-Index),fetch直接支持;XMLHttpRequest需确认服务端允许该 header,否则 CORS 预检失败
真正难的不是切片,而是让每一片都精准落地:边界校验、并发控制、唯一标识、中断恢复——漏掉任一环,上传就只是“看起来在动”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










