multiple属性必须与type="file"共存才支持多文件上传,且form需设enctype="multipart/form-data"和method="POST";name属性须匹配后端解析规则,accept仅作前端提示,校验必须在后端进行。

multiple 属性必须和 type="file" 同时存在
只写 multiple 但没写 type="file",或者写了 type="file" 却漏掉 multiple,浏览器就当单文件处理。哪怕用户按住 Ctrl/Cmd 多选,最终也只提交第一个。
正确写法是:<input type="file" name="files[]" multiple>
-
name带[]是 PHP 场景下的惯用写法,让$_FILES['files']成为数组;Go/Java 等语言不依赖这个,但保留也无害 - 不加
multiple时,input.files.length永远是 0 或 1;加了之后才可能大于 1 - iOS 12 及更早版本对
multiple支持不稳定,部分 Safari 会静默降级为单选——如果目标用户含大量老 iOS 设备,得准备 fallback 提示
form 的 enctype 和 method 缺一不可
enctype="multipart/form-data" 不是可选项,是硬性要求。没它,文件二进制数据根本不会进入请求体,$_FILES 或 req.MultipartForm 全为空。
同时 method 必须是 POST;GET 无法携带文件数据,且 URL 长度限制会导致截断或 414 错误。
立即学习“前端免费学习笔记(深入)”;
- 错误示例:
<form method="post">(缺enctype)→ 后端收不到任何文件 - 错误示例:
<form enctype="multipart/form-data">(缺method)→ 浏览器默认用GET,上传失败 - 调试时直接看 Network → Payload,确认每个文件是否作为独立 part 出现在 multipart body 中,而不是被塞进一个 blob 或消失
name 属性决定后端如何索引文件数组
前端 name 和后端接收逻辑必须匹配。PHP 习惯用 name="files[]",Go 标准库用 name="files" 就能拿到全部,而 Express 默认只认 upload.array('files')。
关键不是方括号本身,而是后端框架怎么解析同名字段:多数框架把重复的 name="files" 当作数组,但 PHP 若写成 name="files"(不带 []),$_FILES['files'] 会是单个文件结构,其余被丢弃。
- PHP 场景下,坚持用
name="files[]",然后遍历$_FILES['files']['name']数组 - Go 场景下,
r.MultipartForm.File["files"]返回[]*multipart.FileHeader,无需改 name - FormData 动态 append 多个文件时,必须用相同 key:
formData.append('files', file1)、formData.append('files', file2)—— 不能改成files[0]、files[1]
accept 属性只起提示作用,不能替代后端校验
accept="image/*" 或 accept=".pdf,.docx" 只影响文件选择对话框的过滤界面,用户仍可通过拖拽、重命名绕过。浏览器也不强制执行 MIME 类型检查。
真正有效的类型控制在后端:读取文件头(magic bytes)、验证扩展名白名单、拒绝 content-type: text/html 的上传等。
- 前端 JS 可读
file.type做初步拦截,但仅用于体验优化(比如立刻报错“不支持该格式”) -
file.type可能为空或伪造(如 .exe 改名成 .jpg),不能信任 - 大文件场景下,别等整个文件传完再校验——考虑流式检测或分片上传时做首块校验
最常被忽略的是:表单提交后,后端是否真的收到了多个文件条目,还是只看到一个。别急着写保存逻辑,先打印 $_FILES 或 req.MultipartForm.File 结构,确认长度和字段完整性——很多“上传失败”其实卡在第一步就没收全。



















