HTML原生不支持直接上传整个文件夹;webkitdirectory仅在Chrome/Edge/Safari中返回扁平化文件列表,依赖webkitRelativePath还原路径但不可靠,Firefox不支持,真需文件夹上传应采用drag & drop + File API递归遍历方案。

HTML 原生不支持通过 直接上传**整个文件夹**(含子目录结构),所谓“上传文件夹”实际是浏览器对 webkitdirectory 属性的支持——它只提供**扁平化文件列表**,不保留路径层级,且兼容性有限。真要实现类似网盘的文件夹拖拽上传,必须组合使用 webkitdirectory、directory(实验性)、或更可靠的 drag & drop + FileList 遍历方案。
为什么 不能真正传文件夹结构
该属性仅在 Chrome/Edge/Safari 中有效,Firefox 完全不支持;它返回的 FileList 中每个 File 对象的 webkitRelativePath 字段理论上含路径,但:
• 服务端无法直接还原目录树,需前端手动解析并补全路径前缀
• 多数后端框架(如 Express multer、Spring MultipartFile)默认只接收扁平文件流,不处理嵌套路径
• webkitRelativePath 在部分版本 Safari 中为空,不可靠
• 若用户手动勾选多个文件而非用文件夹选择,路径信息完全丢失
所以,别依赖 webkitdirectory 做生产级文件夹上传。
用 drag & drop + File API 遍历获取完整路径信息
这是目前最可控、兼容性更好的方式:监听 drop 事件,遍历 event.dataTransfer.items,对每个 FileSystemEntry 递归读取(注意:仅 Chromium 系支持 webkitGetAsEntry;Firefox 用 getAsFile() 只得文件,无路径)。
实操要点:
- 必须在
drop事件中调用event.preventDefault(),否则浏览器会尝试打开/导航 -
item.webkitGetAsEntry()返回FileSystemDirectoryEntry或FileSystemFileEntry,需递归createReader().readEntries() - 每个
File对象可通过file.webkitRelativePath获取相对路径(若有),否则需前端按拖入顺序或文件名模拟层级 - 最终仍要用
FormData逐个append('files', file, fullPath),其中fullPath是你拼出的带斜杠路径字符串(如"project/src/main.js") - 后端必须能解析这个自定义路径字段,不能只依赖原始文件名
后端如何接收并还原文件夹结构?
关键不在前端怎么发,而在后端怎么收和存:
• Node.js(Express + multer):multer 默认不解析 fullPath,需用 multer.memoryStorage() 拿到 Buffer 后,从 req.files[i].originalname 或自定义字段(如 req.body.paths[i])提取路径,再用 fs.mkdirSync(path.dirname(fullPath), { recursive: true }) 创建目录,最后 fs.writeFileSync(fullPath, buffer)
• Java Spring Boot:用 @RequestParam("files") MultipartFile[] files 接收,同时加 @RequestParam("paths") String[] paths,循环写入时根据 paths[i] 构造目标 File 实例
• 注意点:
- 不要直接用
paths[i]拼接系统绝对路径,必须做白名单校验(如禁止"../"、开头不含".")防止路径遍历攻击 - 单次上传大量小文件时,
FormData体积激增,建议前端分批上传(如每 10 个一组) - 服务端需限制最大嵌套深度(如 >5 层拒绝)和总文件数(如 >1000 个拦截)
真正的“无刷新”取决于你是否用了 fetch 或 XMLHttpRequest
只要没提交 到新页面,就属于无刷新。但要注意:
• fetch 不支持上传进度(XMLHttpRequest.upload.onprogress 才行),大文件夹上传建议用 XMLHttpRequest
• 如果你用 iframe 方案(为兼容 IE9),它根本无法处理 webkitdirectory 或拖拽多文件——iframe 只能提交一个表单,而文件夹场景必然涉及动态构造请求体,必须用 JS 控制
• 最容易被忽略的一点:浏览器对 File 对象的引用在上传完成后不会自动释放,大量文件上传后若未手动置空变量(如 file = null),长期运行会内存泄漏
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











