formdata本身不支持流式上传,必须手动分片;它同步构造、将整个file/blob载入内存再序列化为multipart body,无法真正流式处理。

FormData 本身不支持流式上传,必须手动分片
FormData 是一个同步构造的表单数据容器,它把整个 Blob 或 File 对象塞进内存再序列化为 multipart body。哪怕你只调用 file.slice(0, 5 * 1024 * 1024),浏览器仍需在内存中持有一份该切片的完整副本——这不是“流”,是“快照”。所以不存在“基于 FormData 的流式上传”这种说法,强行往里塞 100MB 的 Blob,Chrome 很可能直接抛 RangeError: Maximum call stack size exceeded 或卡死。
真正可行的路径只有一条:用 File.prototype.slice() 切出小块(推荐 2–5MB),每块单独构造一个 FormData 实例,发起独立请求。这不是妥协,是浏览器能力边界决定的硬约束。
- 不要用
ArrayBuffer+new Blob([buf])再塞进 FormData——这会制造两份内存拷贝,极易触发内存警告 - 切片必须用
file.slice(start, end),它返回新Blob,底层由浏览器优化,不立即加载全部内容到 JS 堆 - 切片大小别设成 10MB 以上,Firefox 在 10MB/片时已有明显 UI 卡顿,实测 5MB 是较稳的平衡点
断点续传的关键不在前端,而在服务端是否暴露 /upload/status 接口
前端能做的只是“重试”和“跳过”,无法确认某一片是否真被服务端落盘成功。HTTP 200 只代表请求发出去了、Nginx 接收了、甚至可能只是网关缓存返回的假成功。真正的断点能力取决于服务端是否提供校验接口:
- 上传前必须先
GET /upload/status?uploadId=xxx,拿到已成功写入的chunkIndex列表 - 服务端返回的必须是明确结构,例如
{"uploadedChunks": [0,1,3,4], "totalChunks": 10},不能是笼统的{"status": "success"} - 前端据此跳过已存在的片,只发缺失的;但要注意:服务端对每个
chunkIndex必须做幂等写入(比如先检查uploadId_3.temp是否存在) - 如果服务端没这个接口,或只返回“已上传 7 片”却不告诉你哪 7 片,那前端写的任何“断点逻辑”都是纸糊的
每个分片请求必须携带 uploadId、chunkIndex、totalChunks 三个关键字段
这三个字段是服务端关联、排序、校验、合并的唯一依据。缺一不可,且命名要和服务端约定一致(常见坑:前端叫 chunk_no,后端期待 chunkIndex):
-
uploadId必须在文件选择后立即生成,推荐crypto.randomUUID()(Chrome 91+/Firefox 90+ 支持),降级可用Date.now() + Math.random().toString(36).substr(2, 9) -
chunkIndex从 0 开始还是从 1 开始?必须和服务端对齐;Spring Boot 后端常见从 0 起始,PHP 项目有时从 1,错一位就拼错文件 -
totalChunks不能靠Math.ceil(file.size / chunkSize)算完就扔,得在所有切片循环前算一次并固定下来——因为最后一片往往小于 chunkSize,但序号仍要连续 - 别把
uploadId存 localStorage 了事:同一文件多次上传应生成新 ID,否则旧断点状态干扰新上传
进度不准?别信 XMLHttpRequest.upload.onprogress
XMLHttpRequest.upload.onprogress 只反映浏览器把数据交给操作系统发送队列的速度,不是服务端接收完成时间。网络缓冲、CDN 中转、服务端磁盘写入延迟都会导致进度条“跑太快”——用户看到 100%,其实服务端还没开始处理那片。
真实进度只能靠轮询或服务端推送:
- 最简方案:每片上传成功后,立刻再发一次
GET /upload/status?uploadId=xxx,用返回的uploadedChunks.length / totalChunks更新进度 - 如果服务端支持 WebSocket 或 SSE,可让其在 chunk 写入完成后主动通知前端,避免轮询压力
- 合并阶段不能计入上传进度条——那是服务端任务,前端只应在收到合并成功的回调后才提示“上传完成”
最容易被忽略的是服务端合并逻辑:它必须按 chunkIndex 顺序读取临时文件、拼接、最后做一次 sha256 校验。前端传得再准,服务端拼串错了、漏片了、校验跳过了,上传就等于白干。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










