HTML原生不支持上传整个文件夹,webkitdirectory仅Chromium支持且仅返回扁平化文件列表;需用webkitRelativePath还原路径(但Firefox/Safari不支持),移动端完全无效;强依赖目录结构时应改用ZIP压缩上传方案。

HTML原生不支持上传整个文件夹
浏览器的 <input type="file"> 默认只允许选中单个或多个文件,即使加了 webkitdirectory 或 directory 属性,也仅在部分 Chromium 内核浏览器(如 Chrome、Edge)中触发「选择文件夹」行为,且 Safari、Firefox 完全不支持该能力。这不是 bug,是规范限制:HTML File API 本身未定义“文件夹对象”,FileList 里只有 File 实例,没有 Directory。
webkitdirectory 的实际行为和兼容性陷阱
加了 webkitdirectory 后,用户点击选择的是一个文件夹,但浏览器实际返回的是该目录下**所有文件的扁平化列表**(不含子目录结构),且每个 File 对象的 webkitRelativePath 属性会保留相对路径(例如 "docs/report.pdf")。这个属性在 Firefox 中为 null,Safari 中根本不存在。
- 必须用
input.files获取全部文件,不能依赖input.files[0].files这类错误写法 -
webkitRelativePath是唯一能还原层级的线索,但不可靠——用户可能拖拽进来的文件本身就没路径信息 - 服务端若需还原目录结构,必须由前端把
webkitRelativePath作为元数据随文件一起传过去 - 移动端(iOS/Android)完全无视该属性,点选操作直接退化为单文件选择
按文件类型分流上传的可行做法
所谓“分流”,本质是前端拿到 File 列表后,用 file.type 和 file.name 做判断,再分组调用不同接口或 FormData 字段名。注意:file.type 不可靠,尤其对 Office 文档(常为空字符串或 application/octet-stream),必须结合后缀名校验。
- 推荐用正则匹配
file.name.toLowerCase().match(/\.[a-z0-9]+$/)提取扩展名,比file.type更稳定 - PNG/JPG/GIF 等图片可走
/api/upload/image;PDF 走/api/upload/pdf;.xlsx/.docx 统一走/api/upload/office - 避免在循环中并发发请求,容易触发浏览器限流或服务端频率拦截,建议用
Promise.allSettled()控制并发数(如每次最多 3 个) - 如果后端要求同一请求里混传多种类型,就用同一个
FormData,但给每个append()的 key 加类型前缀,比如form.append("image_file_1", file)
真正需要目录结构时的替代方案
如果你的业务强依赖“上传整个文件夹并保留嵌套关系”,HTML 原生方案已到极限。这时候该换思路:
立即学习“前端免费学习笔记(深入)”;
- 引导用户压缩成 ZIP,前端用
JSZip解包,再逐个读取内部文件——能拿到完整路径、内容、MIME,且兼容所有浏览器 - 桌面端场景可考虑 Electron/NW.js,直接调用 Node.js 的
fs.readdir,绕过浏览器沙箱 - 移动端只能放弃目录概念,改用“多选文件 + 手动分组标签”方式,由用户自己标记哪些是图片、哪些是文档
别在 webkitdirectory 上死磕兼容性,它从来就不是标准功能,只是 Chromium 的实验性扩展。真正上线的系统,ZIP 方案的确定性和可控性远高于依赖浏览器私有属性。



















