必须设为multipart/form-data,否则前端根本不会发送文件;浏览器默认用application/x-www-form-urlencoded编码,仅传文件路径而非二进制内容。

必须设为 multipart/form-data,否则文件根本不会发出——不是后端收不到,是前端压根没发。
为什么 enctype="multipart/form-data" 不可省略
浏览器默认用 application/x-www-form-urlencoded 编码表单,它会把所有字段 URL 编码成 a=1&b=hello%20world 这类字符串。遇到 <input type="file">,它只传个空值或 C:\fakepath\abc.jpg 这种路径字符串,二进制内容直接丢弃。
multipart/form-data 是唯一能让浏览器把文件切分成带 Content-Disposition 和真实 Content-Type 的二进制块(part)的编码方式,中间用随机 boundary 分隔。没有它,HTTP 请求体里连 boundary= 都看不到。
- 漏写或拼错(如
mutlipart/form-data)→ 后端req.files或request.FILES为空 - 写在
<input>上(如<input enctype="">)→ 完全无效 - 用 GET 提交 → 浏览器静默忽略
enctype,文件字段被丢弃
enctype 必须写在 <form></form> 标签上,且大小写要对
它只作用于整个表单,不能继承、不能动态补加、不能靠 JS 提交时“事后弥补”。HTML 不区分大小写,但写成 MULTIPART/FORM-DATA 容易被误读为拼写错误,统一小写最稳妥。
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确:
<form action="/upload" method="post" enctype="multipart/form-data"></form> - ❌ 错误:
<form enctype="MUTIPART/FORM-DATA"></form>(大小写混乱) - ❌ 错误:
<form><input enctype="multipart/form-data"></form>(属性位置错) - ⚠️ 动态创建表单时:
const form = document.createElement('form'); form.enctype = 'multipart/form-data';,不设就还是默认编码
用 fetch + FormData 时,enctype 属性其实不生效
原生表单提交才看 <form enctype></form>;用 JS 手动发请求时,起作用的是你构造的数据对象。只要用了 new FormData(formElement) 或 FormData.append('file', input.files[0]),浏览器会自动设置 Content-Type: multipart/form-data; boundary=...。
- ✅ 正确:
fetch('/upload', { method: 'POST', body: new FormData(form) }) - ❌ 错误:
fetch('/upload', { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) })→ 文件变[object File] - ❌ 错误:手动设
headers: { 'Content-Type': 'multipart/form-data' }→ 丢失boundary,后端解析失败 - ⚠️
FormData.append()第二个参数必须是File实例,不是input.value(那是只读路径字符串)
name 属性漏写、大小写不一致,也会让文件“消失”
后端靠每个 part 的 Content-Disposition: form-data; name="avatar"; filename="a.jpg" 里的 name 字段来映射数据。这个 name 必须和后端代码里取值的 key 完全一致(大小写、空格、下划线都算不同)。
- ❌
<input type="file" name="Avatar">,后端却写req.file('avatar')→ 找不到 - ❌
<input type="file">没写name→ 该 part 被跳过,后端完全感知不到 - ✅ 多文件上传:
<input type="file" name="files" multiple>→ 后端收到数组,不是file[] - ⚠️
accept和multiple都只是前端提示,不影响实际传输;绕过它们太容易,后端校验 MIME 类型和魔数才是关键
最容易被忽略的是:表单嵌在框架(如 ASP.NET Master Page、React 的 Portal、Vue 的 Suspense)里时,enctype 必须出现在最终渲染出的最外层 <form></form> 上——中间任何一层抽象都可能吞掉这个属性,而 DevTools 里未必一眼看得出来。


















