必须显式设置enctype="multipart/form-data"且method为post(或put等带body的方法),否则浏览器根本不会发送文件;默认application/x-www-form-urlencoded编码会丢弃二进制内容,仅传空值或fakepath字符串,而multipart/form-data才能将文件切分为带Content-Disposition和真实Content-Type的二进制块。

enctype="multipart/form-data" 必须显式写在 <form> 标签上,且 method 必须为 post(或 put 等带 body 的方法),否则文件根本不会发出——不是后端收不到,是前端压根没传。
为什么 enctype 必须设为 multipart/form-data
浏览器默认用 application/x-www-form-urlencoded 编码表单,它把所有字段转成 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只作用于整个表单,不能继承、不能动态补加、不能靠 JS 提交时“事后弥补”
enctype 必须写在 <form> 标签上,大小写和位置都不能错
HTML 不区分大小写,但写成 MULTIPART/FORM-DATA 容易被误读为拼写错误;统一小写最稳妥。
常见错误包括:
-
<form method="post" enctype="MULTIPART/FORM-DATA">❌ 大小写混乱 -
<form method="get" enctype="multipart/form-data">❌GET没有请求体,enctype被忽略 -
<form method="post"><input enctype="multipart/form-data"></form>❌ 属性位置错
动态创建表单时:const form = document.createElement('form'); form.enctype = 'multipart/form-data';,不设就还是默认编码。
立即学习“前端免费学习笔记(深入)”;
用 fetch + FormData 时,enctype 属性本身不生效
原生表单提交才看 <form enctype>;用 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] - ❌ 错误:
fetch('/upload', { headers: { 'Content-Type': 'multipart/form-data' } })→ 丢失boundary,后端解析失败 - ⚠️
FormData.append()第二个参数必须是File实例,不是input.value(那是只读路径字符串)
真正容易被忽略的是:它是个“表单级开关”,断在第一环就全链路失效
一旦 enctype 没配对,整个上传链路在第一环就断了——浏览器根本不打包文件内容,后续无论后端用 multer、Flask.request.files 还是 @RequestPart 都收不到东西。
调试时别急着查后端日志,先打开 Chrome DevTools → Network → 点开请求 → Headers → 看 Content-Type 是不是 multipart/form-data; boundary=;如果不是,问题一定出在前端表单配置或 JS 请求构造上。



















