浏览器原生文件夹上传依赖非标准属性webkitdirectory,需配合directory和multiple使用,通过file.webkitRelativePath还原目录结构,Firefox不支持。

浏览器原生支持文件夹上传,但仅限于 Chrome、Edge、Safari(部分版本)等现代浏览器,Firefox 不支持 webkitdirectory;它不是“上传整个文件夹”这个动作本身被标准化了,而是靠 webkitdirectory 这个非标准但广泛实现的属性触发递归读取行为。
为什么 webkitdirectory 是关键入口
普通 <input type="file"> 只能选文件,加 multiple 也只是多选文件,无法保留目录层级。而加上 webkitdirectory 属性后,用户点击选择的是一个文件夹,浏览器会自动遍历其下所有文件(不包括子文件夹本身),并为每个 File 对象提供 webkitRelativePath 字段——这才是还原原始结构的唯一依据。
-
webkitdirectory必须和directory同时存在,且multiple建议带上(兼容性更稳) - HTML 写法必须是:
<input type="file" webkitdirectory directory multiple>,缺一不可 - 该属性在 Safari 中从 16.4+ 开始支持,在 Edge 中稳定可用;Firefox 完全忽略,会退化为单文件选择
- 用户看到的 UI 仍是“选择文件夹”,但底层拿到的是扁平化的
FileList,需靠file.webkitRelativePath拼出路径
如何正确提取带路径的文件列表
监听 change 事件后,不能直接用 files[i].name 当作完整路径——它只是文件名,不含父级目录。必须依赖 file.webkitRelativePath,它返回类似 "project/images/logo.png" 的字符串,可直接用于服务端重建目录结构。
- 如果
file.webkitRelativePath为空字符串,说明该文件位于根目录(即用户直接选中的那个文件夹下),不是子目录里的 - 某些旧版 Chrome 可能对空路径处理不一致,建议统一 fallback 到
file.name - 不要尝试用
file.path或file.fullPath——它们在标准 File API 中不存在,是过时或非安全 API - 示例提取逻辑:
for (let i = 0; i < files.length; i++) { const file = files[i]; const path = file.webkitRelativePath || file.name; fileList.push({ path, file }); }
服务端怎么重建目录结构?
前端传来的每个文件都附带了相对路径,后端收到后不能直接拼到磁盘路径里,否则有路径遍历风险(比如 ../../etc/passwd)。必须做白名单校验和路径规范化。
立即学习“前端免费学习笔记(深入)”;
- 先用语言内置函数做路径净化,例如 Node.js 的
path.normalize(),Python 的os.path.normpath() - 检查净化后路径是否仍以
..开头,或包含非法段(如../、/../) - 强制限定根目录前缀,例如只允许保存到
/uploads/2026/下,所有path都要拼接在这个前缀之后 - 创建子目录时使用递归 mkdir(如 Node.js 的
fs.mkdirSync(..., { recursive: true })),避免因中间目录缺失报错
真正容易被忽略的是路径注入防御——很多开发者拿到 webkitRelativePath 就直接 fs.writeFile(path),这等于把用户可控字符串当成本地路径执行,只要构造特殊文件名就能写到任意位置。安全边界必须由后端严守,前端只负责传递原始信息。



















