form 的 enctype 必须设为 multipart/form-data,否则无法传输二进制文件;input type="file" 必须有 name 属性才能提交;multiple 上传需后端适配多文件解析;accept 等前端限制可被绕过,安全校验必须在后端实现。

form 的 enctype 必须设为 multipart/form-data
浏览器默认用 application/x-www-form-urlencoded 编码表单,这种编码无法传输二进制文件。不改这个值,后端根本收不到文件内容,request.files 或等价结构永远为空。
实操建议:
- 显式声明
enctype="multipart/form-data",不要依赖浏览器默认 - 如果同时提交文本字段和文件,必须用这个编码,没有例外
- 某些前端框架(如 Vue + axios)会自动处理,但原生
<form>必须手动写
input type="file" 要加 name 属性
没有 name 的 <input type="file"> 不会作为表单数据提交,后端完全感知不到——连空字段都不会收到。
常见错误现象:
立即学习“前端免费学习笔记(深入)”;
- 点击上传按钮没反应,控制台无报错,但后端日志里找不到该字段
- 用了
id但漏了name,误以为 ID 就够了
正确写法示例:
<input type="file" name="avatar" accept="image/*">
accept 是可选但强烈建议加的,它限制文件类型提示,不影响后端校验,但能减少用户误选。
后端接收时注意多文件与单文件的差异
HTML 中 <input type="file" multiple> 会让浏览器发送多个文件,但不同后端框架对同名多文件的解析方式不同:
- Express(Node.js):需用
multer,single()vsarray()中间件行为完全不同 - Flask(Python):
request.files.get('files')只拿第一个,要用request.files.getlist('files') - PHP:
$_FILES['files']['name']是数组,但结构是二维索引数组,不是扁平列表
容易踩的坑:前端写了 multiple,后端却只调一次 get(),结果只拿到一个文件。
安全边界不能只靠前端限制
accept、maxFiles、size 等属性全在前端,用户禁用 JS 或用 curl 直接发请求就能绕过。真正有效的校验必须落在后端。
关键点:
- 检查
Content-Type是否为multipart/form-data,且含boundary - 验证文件扩展名和实际二进制头(magic bytes),比如用
file-type(JS)或python-magic(Python) - 限制单文件大小(如 Nginx 的
client_max_body_size,或 Express 的limits: { fileSize: 5 * 1024 * 1024 })
上传路径别直接拼用户传的文件名,否则可能触发路径遍历;用 UUID 重命名最稳妥。



















