像我们这种经常跟上传接口打交道的人,最怕听到一句话就是“文件传不上去”。尤其是大文件,传一半断了、服务器超时、用户对着一个转了十分钟的进度条发火,这种场景我见得太多了。后来我把同事的上传模块整个重构成了一套文档上传分片接口,核心就是把一个大文件切开,一块一块传,传完再拼起来。这篇文章就把这套接口的设计思路、协议定义、前后端实现细节和踩过的坑一次讲清楚,适合后端开发、前端工程师、全栈以及所有被大文件上传折磨过的人参考。
1. 为什么大文件上传必须分片
很多人第一次听到“分片上传”会觉得没必要:我直接用 POST 把整个文件丢给后端不行吗?小文件确实没问题,但一旦文件上了几百 MB,问题就全冒出来了。
1.1 不分片上传的致命伤
我最早接手的那版系统就是这么干的,前端拿到 File 对象,FormData 直接 append,然后 axios post 给后端。最初用着挺正常,直到有人开始传一个 1GB 的设计稿压缩包,问题集中爆发:
- 请求超时。很多网关和 Web 容器默认的请求超时时间是 30 到 60 秒,网络稍微不稳定,一条请求就没了,用户看到的是“上传失败”四个大字。
- 重传成本高。传一半断了,下次还得从头来,1GB 文件传了三回还是失败,用户心态直接崩。
- 服务器压力大。后端一次性把整个文件读进内存再落盘,并发一高,内存蹭蹭往上涨,Java 里最容易 OOM,Node.js 里就是进程直接挂。
- 无法判断进度。浏览器里的上传进度条看着走了 99%,其实那是伪进度,服务端写盘失败的场景根本感知不到。
1.2 分片到底解决了什么问题
分片上传的本质是把“一次巨大请求”拆成“多次小请求”。文件被切成 N 块,前端一块一块发,后端一块一块收,最后再合并成一个完整文件。这样带来的直接变化是:单次请求的数据量小了,超时概率大幅下降;传失败的片可以单独重传;服务端也可以做并发控制;用户还能看到真实的、分片维度的进度条。
另外,分片之后还能顺带实现两个特别香的特性:一个是秒传,上传前先算文件指纹,如果服务器上已经有相同内容的文件,直接跳过上传;另一个是断点续传,网络断了之后再打开,已经传完的片不用重新传,只补剩余片段。这两个功能对大文件场景是刚需,也是分片设计最大的红利。
1.3 哪些场景最需要分片接口
我自己的判断标准很简单:文件经常超过 100MB、用户网络环境比较复杂(比如弱网、移动网络)、或者有音视频和大型文档类业务,就应该考虑分片。像网盘、在线文档协作、视频制作平台、简历附件上传这类系统,分片上传几乎属于标配。如果你的系统只是传些几十 KB 的图片,那确实没必要杀鸡用牛刀,普通 FormData 就够。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 接口整体设计:先定协议再写代码
动手写路由之前,我习惯先把接口协议定义清楚。因为分片上传涉及的接口不止一个,如果没有一份清晰的接口文档,前后端联调就是灾难。
2.1 一份好的接口文档必须包含什么
我做接口设计时,四个东西必须写明白:接口的 URL 和方法、请求参数含义、响应结构、错误码定义。这套分片上传看似简单,实际接口有五个:创建任务、上传分片、查询进度、合并文件、取消任务。每个接口都需要把参数表列清楚,否则前端传参和后端接收字段对不上,排查一整天都查不出结果。
我自己见过最差的“接口文档”,就一句话:“POST /upload 上传文件”,参数、错误码一概没有,联调时全靠猜和扒代码。分片接口最忌讳这种文档,因为分片涉及序号、总分片数、文件标识等多个参数,缺一个都会导致合并异常。
2.2 核心接口清单与参数定义
下面是我在实际项目中稳定运行过的一套接口协议,可以直接作为基础模板。
| 接口名 | 方法 | 路径 | 作用 |
|
