不能。html5原生input file不支持文件夹上传,仅webkitDirectory(chrome/safari/edge)等私有属性可递归读取文件并用webkitRelativePath保留路径,但非标准、firefox不支持,需后端按路径重建结构并校验安全。

html5 能否原生上传文件夹?
不能。标准 HTML5 的 默认只支持单文件或多个文件(通过 multiple),但不支持选择整个文件夹——浏览器会直接禁用文件夹选项,或忽略其路径。只有显式启用 webkitdirectory(Chrome/Safari/Edge)或 directory(Firefox 早期曾支持,现已移除)时,才可能触发文件夹选择行为,且该能力非标准、不可靠。
webkitdirectory 是什么?怎么用?
它是 WebKit 内核浏览器(Chrome、Edge、Safari)私有属性,允许用户在文件选择对话框中勾选「文件夹」并递归读取其下所有文件。但它不上传文件夹结构本身,只提供一组 File 对象,每个对象的 webkitRelativePath 属性保留相对路径(如 "src/main.js"),这是还原目录结构的唯一依据。
- 必须加
webkitdirectory和directory双属性(兼容性写法) - 不能与
multiple混用(部分浏览器会失效) - 仅响应用户主动点击选择,无法通过 JS 触发(安全限制)
-
webkitRelativePath在 Firefox 中始终为空,directory属性已废弃
如何用 javaScript 读取并上传整个文件夹?
核心是遍历 Event.target.files 得到的 FileList,提取每个 File 的 webkitRelativePath,构造带路径前缀的 formData,并逐个提交(或合并为一个请求)。注意:不能直接传 FileList 给后端,需手动处理路径和分块。
- 用
for...of遍历files,避免类数组陷阱 - 每个
File的name是纯文件名,webkitRelativePath才含层级(如"assets/img/logo.png") - 上传时建议将
webkitRelativePath作为字段(如form.append('path', file.webkitRelativePath))传给后端解析 - 大文件夹需考虑并发限制和内存占用,避免一次性读取全部
File的ArrayBuffer
document.getElementById('folderInput').addEventListener('change', (e) => { const files = e.target.files; const formData = new FormData(); for (const file of files) { formData.append('files', file, file.webkitRelativePath || file.name); } fetch('/upload', { method: 'POST', body: formData }); });
后端接收时要注意哪些关键点?
前端传来的只是扁平化的文件流 + 路径字符串,后端必须自行重建目录结构。常见坑:multipart/form-data 中同名字段(如都叫 files)会被合并或覆盖,必须确保每个文件有唯一标识或显式携带路径字段。
立即学习“前端免费学习笔记(深入)”;
- Node.js(express + multer):默认不解析
webkitRelativePath,需自定义storage.filename或用multer.fields()分离路径字段 - python(flask):从
request.form.getlist('path')和request.files.getlist('files')一一对应还原 - php:
$_FILES['files']['name']是原始名,路径需额外字段传入,否则无法区分a.txt和sub/a.txt - 路径校验必须做:拒绝
../、空路径、非法字符,防止路径遍历攻击
真正难的不是前端选文件夹,而是服务端安全、可靠地把一堆扁平文件按原始层级落地。很多项目卡在这一步,不是因为不会写 webkitdirectory,而是没处理好路径映射和权限控制。