一句话定义:multipart/form-data 是 HTTP 请求体(request body)的一种编码格式,它把一次请求里要发送的多段内容,包括普通文本字段和文件,分别打包成一个个独立的分件(part),再用一串随机生成的边界字符串(boundary)把它们隔开,最后整体装进同一个请求里发出去。
这层包装如何工作
可以先把一次上传设想成寄一个纸箱,箱子里放了好几样东西。每一件都贴一张小标签,标签上写明它叫什么(name="avatar")、原文件名是什么(filename="cat.png")、内容类型是什么(Content-Type: image/png);各件之间用一条特制的封箱胶带隔开,胶带上印着一串几乎不可能与箱内物品文字重复的随机字符,这就是 boundary。服务端收到纸箱后,按照胶带的位置把各件剪开,逐件读出标签和内容。boundary 必须同时出现在请求头 Content-Type: multipart/form-data; boundary=----xyz123 和请求体的分隔行里,两边一旦不一致,服务端就找不到切口,只能返回解析失败。
和 JSON 的区别
两者都放在 HTTP 请求体里,但编码方式完全不同。
| 维度 | application/json | multipart/form-data |
|---|---|---|
| 结构 | 一整块结构化文本 | 容器,内含多个带独立头部的分件 |
| 解析 | 一次性反序列化 | 流式逐段解析(streaming parser) |
| 二进制 | 需 base64,体积约涨三分之一 | 原样二进制直传 |
| 典型用途 | 结构化参数、API 调用 | 表单 + 文件一起提交 |
用 JSON 传文件时,通常先把文件转成 base64 字符串塞进字段里。这样做的好处是“一个接口、一种格式”,代价是体积膨胀、内存翻倍,大文件尤其吃不消。multipart 则把文件按原始字节直接流过去。
问题大多出在这层包装上
- 解析失败:最常见的是手写请求头,把自动生成的
Content-Type(里面带 boundary)覆盖成了不带 boundary 的版本;或者自己拼请求体时,忘了每行必须以\r\n结尾。 - 大小限制:网关、反向代理、应用框架往往各自设了请求体上限(例如 Nginx 的
client_max_body_size),超了就是 413 或连接被截断。线上“上传到 99% 失败”,通常就是撞上了某一层限制。 - 超时:上传耗时取决于上行带宽,长连接容易被中间设备的空闲超时掐断;重试时要注意接口是否幂等,否则可能产生半截文件。大文件一般改用分片上传(chunked upload),把一个大请求拆成多个小请求。
实际意义
调接口前先看文档写的是 multipart 还是 JSON,别拿 base64 硬套;排查上传问题时,先看请求头里的 boundary 在不在、和目标地址的上限对不对,再怀疑网络。对普通职场人来说,网页传大文件失败,往往不是“网不好”,而是这层包装被大小或时间限制拦下了:压缩一下、换个分片上传的入口,通常就过了。具体限制值以各平台官方页面为准。
