HTML无法原生上传文件夹结构,需用webkitdirectory属性(Chrome/Edge/Firefox支持)配合directory和multiple属性实现,选中后通过file.webkitRelativePath获取相对路径,再结合FormData上传路径与文件本体,后端须校验并安全解析路径以防遍历攻击。

HTML 本身不能直接上传文件夹——input[type="file"] 默认只支持单文件或多个文件,**不递归包含子目录结构**。要上传“含代码工程的文件夹”,必须靠浏览器支持的 webkitdirectory 属性(Chrome/Edge/Firefox 支持),或前端手动遍历 + 后端还原路径逻辑。否则你拿到的只是平铺的一堆文件,丢失所有层级关系。
用 webkitdirectory 选中整个文件夹(最简方案)
这是目前唯一原生、零依赖、能保留路径的 HTML 方式,但仅限用户主动选择一个文件夹(不是拖拽整个工程目录进去):
- 必须显式添加
webkitdirectory和directory两个属性,缺一不可:<input type="file" webkitdirectory directory multiple> - 触发后,浏览器弹出的是「选择文件夹」对话框(不是文件),选中后
event.target.files返回的每个File对象都带webkitRelativePath属性,例如"src/main/java/com/example/App.java" - 注意:Safari 不支持;IE 完全不支持;移动端(iOS/Android)基本无效
- 常见错误现象:加了
webkitdirectory却没反应 → 检查是否漏了multiple;或者用了display: none隐藏 input 导致 click 失效(见下条)
webkitRelativePath 怎么用?别直接发给后端
这个路径是只读字符串,不能当本地文件系统路径用,也不能直接 fetch 读取内容。它只是个提示,告诉你“这个文件在原始文件夹里位于哪一层”。真正上传时,你要:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 遍历
event.target.files,对每个File实例调用file.webkitRelativePath获取路径 - 用
FormData.append()把路径作为额外字段传过去,比如:fd.append("path", file.webkitRelativePath) - 同时 append 文件本体:
fd.append("file", file)(注意:同一个FormData可以多次append("file", ...),后端靠路径字段区分归属) - 别试图用
file.path或file.fullPath—— 这些在现代浏览器里已被移除或始终为空
后端怎么还原文件夹结构?关键在路径解析
前端传来的 webkitRelativePath 是相对路径字符串,后端不能盲目拼到磁盘路径里,否则有路径遍历风险(如 "../../../etc/passwd")。正确做法:
立即学习“前端免费学习笔记(深入)”;
- 先做白名单校验:用正则判断路径是否只含字母、数字、
/、-、_、.,且不以../或/开头 - 用语言内置安全函数解析:Python 用
os.path.normpath()+os.path.relpath(),Node.js 用path.posix.resolve()再检查是否仍在目标根目录下 - 实际存储时,把路径转为哈希前缀(如
sha256(project_name).hex[:8]/src/main/...),避免同名工程覆盖或恶意路径冲突 - 别指望
multer或Flask-Uploads自动处理层级——它们默认只存文件名,路径逻辑必须自己写
真正容易被忽略的点是:即使用了 webkitdirectory,用户仍可能取消选择、只选中空文件夹、或选中符号链接(webkitRelativePath 会返回 "")。这些边界情况前端不校验,后端就收不到任何 path 字段,直接 400 或静默失败。


















