原生HTML不支持文件夹上传+秒传一体化,因webkitdirectory扁平化文件且无法直接计算哈希;需前端用FileSystemDirectoryHandle遍历并分文件计算SHA256,后端按文件粒度校验并返回跳过/上传列表。

原生 HTML 不支持真正意义上的「文件夹上传 + 秒传」一体化实现,webkitdirectory 和 directory 属性只能扁平化读取子文件,不保留路径结构,且无法触发秒传所需的文件内容哈希计算(如 MD5/SHA256)。要达成目标,必须前后端协同:前端用 File API 遍历目录树并计算每个文件的哈希值,后端提供秒传校验接口。纯 HTML 标签做不到。
为什么 webkitdirectory 不能直接用于秒传
Chrome/Safari 支持 ,但返回的 input.files 是扁平化的 FileList,所有子文件都混在一起,丢失层级信息;更重要的是:File 对象本身不暴露原始字节流,无法在不读取全量内容的前提下计算 MD5 —— 而秒传依赖这个哈希值做服务端比对。强行调用 file.arrayBuffer() 会阻塞主线程、卡死大文件夹(比如含 1000 个 10MB 文件),用户根本点不动。
前端必须手动遍历目录并分文件计算哈希
需用 FileSystemDirectoryHandle(仅 Chromium 系列支持)或降级 fallback 到 webkitdirectory + 后续路径解析逻辑。关键步骤如下:
- 调用
showDirectoryPicker()获取DirectoryHandle,再递归handle.values()遍历所有FileSystemFileHandle - 对每个
fileHandle调用getFile()得到File实例,再用FileReader或file.arrayBuffer()读取内容 - 使用
SubtleCrypto.digest('SHA-256', buffer)计算哈希(注意:MD5 不被 Web Crypto API 原生支持,需引入第三方库或降级) - 将每个文件的
name、relativePath(需自己拼接)、size、sha256打包为 JSON 发送给后端校验
后端秒传校验接口必须按文件粒度响应
不能只校验整个文件夹的“总哈希”,因为秒传的本质是避免重复上传已存在文件。服务端需:
- 接收前端发来的文件列表(含每个文件的相对路径、大小、SHA256)
- 逐个查询数据库或对象存储中是否已存在相同
sha256 + size的文件记录 - 返回一个结构体,例如:
{ "skipped": ["a/b.txt", "c/d.jpg"], "needUpload": ["e/f.pdf"] } - 前端根据该响应跳过已存在文件,只上传
needUpload中的文件,并在请求头或 body 中显式携带relativePath字段,服务端据此还原目录结构
真正的难点不在上传,而在路径重建与并发控制
即使秒传逻辑跑通,服务端合并时仍面临两个硬伤:一是浏览器不提供标准 API 获取文件在原始文件系统中的完整路径(file.webkitRelativePath 仅在 webkitdirectory 下部分可用,且不可靠);二是多文件并发上传时,若某个文件秒传成功、另一个失败,整个文件夹状态就处于不一致中间态。实践中必须引入上传会话 ID(session_id)+ 事务性状态表,否则用户刷新页面后无法准确恢复进度。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











