← 返回题目列表

multipart/form-data 是怎么上传文件的?和 application/json、表单编码有什么区别?

中等 第 26 / 32 题 更新于 2026/08/02
HTTP文件上传表单

简化版

multipart/form-data 是浏览器表单上传文件时常用的请求体格式。

它会用一个 boundary 把请求体拆成多个 part,每个 part 都可以有自己的头信息,例如字段名、文件名、内容类型。普通文本字段和文件字段可以放在同一次请求里。

它适合上传二进制文件;application/x-www-form-urlencoded 更适合简单表单;application/json 更适合结构化 API 数据,但不能天然表达文件流。

详细版

典型请求头:

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryabc

请求体中每个 part 由 boundary 分隔:

------WebKitFormBoundaryabc
Content-Disposition: form-data; name="name"

resume
------WebKitFormBoundaryabc
Content-Disposition: form-data; name="file"; filename="a.pdf"
Content-Type: application/pdf

...binary...
------WebKitFormBoundaryabc--

boundary 不能和正文内容冲突,最后一个 boundary 后面有 -- 表示结束。

文件上传接口常见问题包括大小限制、文件类型校验、临时文件存储、流式处理、安全扫描和超时控制。

完整版教学

1. 先说明 multipart 的本质

multipart/form-data 的核心是“一个 HTTP 请求体里包含多个独立片段”。

每个片段叫 part。

每个 part 可以表示一个普通字段,也可以表示一个文件。

浏览器提交带文件的表单时,一般会选择这种格式。

看到 multipart,就要想到 boundary 分隔、多 part、每个 part 有自己的头。

2. boundary 是怎么工作的

请求头会指定边界字符串:

Content-Type: multipart/form-data; boundary=----abc123

请求体里用这个边界切分内容:

------abc123
Content-Disposition: form-data; name="username"

tom
------abc123
Content-Disposition: form-data; name="avatar"; filename="me.png"
Content-Type: image/png

...binary bytes...
------abc123--

最后一段边界后面多出的 -- 表示整个 multipart body 结束。

服务端解析时会按照 boundary 拆分,然后分别读取每个 part 的元信息和内容。

3. Content-Disposition 很关键

每个 part 通常会带:

Content-Disposition: form-data; name="file"; filename="a.txt"

其中 name 是表单字段名,filename 是客户端上传时提供的文件名。

文件 part 还可能带:

Content-Type: text/plain

服务端不能盲信这些字段。

文件名可能包含特殊字符,Content-Type 也可能被伪造。

4. 和其他请求体格式对比

格式Content-Type适合内容特点
表单编码application/x-www-form-urlencoded简单键值对字段会 URL 编码
JSONapplication/json结构化数据易读,适合 API
multipartmultipart/form-data文件 + 表单字段支持二进制和多 part
原始流application/octet-stream单个二进制流元信息要另行传递

如果只是提交 {name, age},JSON 或表单编码都可以。

如果要同时传 userId 和文件,multipart 更自然。

5. 服务端处理文件上传的工程点

文件上传不是只解析 body。

服务端还要考虑:

  • 最大请求体大小,例如限制 20MB。
  • 单文件大小和文件数量限制。
  • 文件类型白名单。
  • 文件名规范化,避免路径穿越。
  • 临时目录清理。
  • 大文件流式写入,避免一次性读入内存。
  • 上传后异步扫描或转码。

这些点经常是面试追问,因为它们连接协议和工程安全。

6. 安全风险不能忽略

上传文件最危险的点是“把用户提供的字节当可信内容”。

常见风险包括:

  • 上传脚本文件后被服务器执行。
  • 文件名包含 ../ 造成路径穿越。
  • 伪造 Content-Type 绕过校验。
  • 超大文件压垮磁盘。
  • 图片木马或恶意压缩包。

服务端应该使用随机文件名、独立对象存储、白名单校验、大小限制、权限隔离。

7. 常见误区与追问

  • 误区:multipart 只能上传一个文件。 它可以包含多个文件 part,也可以混合普通字段。
  • 误区:filename 就是安全文件名。 客户端传来的文件名不可信,不能直接拼路径。
  • 误区:Content-Type 能证明文件真实类型。 它可以被伪造,必要时要检查魔数或做安全扫描。
  • 追问:boundary 为什么必须出现在请求头里? 服务端需要它来准确切分请求体中的多个 part。
  • 追问:JSON 能不能上传文件? 可以用 Base64 等方式绕,但体积变大且不适合大文件。
  • 追问:大文件为什么要流式处理? 一次性读入内存会造成内存峰值和稳定性问题。

8. 加强记忆

multipart 的记忆模型是:一个大包裹,boundary 是隔板,每个 part 是一个小包。

答题时按 boundary、part 头、格式对比、服务端安全 4 层展开即可。