multipart/form-data 是浏览器上传文件时唯一合法的编码格式,它通过边界分隔符将文本字段与二进制文件分开,使服务端能准确提取原始字节;若误用 application/json 或 x-www-form-urlencoded,文件会被转为字符串导致乱码或丢失。

multipart/form-data 是什么,为什么不能用 application/json 传文件
浏览器表单提交文件时,enctype="multipart/form-data" 不是可选项,而是唯一合法方式。它把整个请求体拆成多个“部分”(part),每个 part 带自己的头部(如 Content-Disposition: form-data; name="file"; filename="a.jpg")和二进制内容,这样服务端才能区分字段和文件、提取原始字节。
如果错设成 application/json 或 application/x-www-form-urlencoded,浏览器会尝试把文件转成字符串(比如 base64 或 [object File]),后端收到的只是乱码或空值,req.file 或 request.files 根本不会存在。
- 只有
multipart/form-data允许混合文本字段 + 二进制文件 -
application/json只能传 JSON 字符串,不支持二进制边界分隔 - 表单中只要有一个
<input type="file">,enctype就必须设为multipart/form-data
HTML 表单里怎么正确写 enctype
关键点:不是加在 <input> 上,而是写在 <form> 标签上;且必须配合 method="POST" —— GET 不允许上传文件。
<form action="/upload" method="POST" enctype="multipart/form-data"> <input type="text" name="title"> <input type="file" name="avatar"> <input type="file" name="photos" multiple> <button type="submit">上传</button> </form>
- name 属性值(如
avatar)会成为后端接收时的字段键名 - 多个同名
file输入(带multiple)会被打包成文件数组,不是单个对象 - 不要手动设置
Content-Type请求头 —— 浏览器会自动生成带随机 boundary 的值,比如multipart/form-data; boundary=----WebKitFormBoundaryabc123
后端解析 multipart/form-data 的常见陷阱
Node.js(Express)默认不解析 multipart,需用 multer;Python Flask 需检查是否调用 request.files.get() 而非 request.form.get();PHP 则要确认 $_FILES 是否非空且 error === 0。
- Express + multer:必须显式配置
dest或storage,否则文件不会落地,req.file为 undefined - 文件过大时,Nginx 默认限制 1MB,会返回 413 Request Entity Too Large,需改
client_max_body_size - 前端若用
fetch提交 FormData,不能手动设Content-Type头,否则浏览器不会注入 boundary,导致后端解析失败 - 字段名大小写敏感:前端传
name="File",后端就该用req.files.File,不是file
什么时候不该用 multipart/form-data
纯 API 场景下,比如移动端上传或前后端完全分离项目,更推荐用 base64 编码或直接传二进制流(Content-Type: image/jpeg),再配合签名、分片、断点续传等能力 —— multipart/form-data 的边界解析开销大、难调试、不便于 CDN 缓存和代理转发。
- 小图标(
- 大文件上传应避开表单,改用
PUT直传或 TUS 协议 - 如果后端只接受 JSON,又必须传文件,说明接口设计已偏离 REST 原则,得协调重构
boundary 字符串本身不可预测,不同浏览器、不同版本生成规则不同,任何硬编码 boundary 的解析逻辑都会失效 —— 这是最容易被忽略、也最难排查的一点。

















