先记住这个答案
File.name 是用户本机文件名,不同目录或不同文件可同名;lastModified 由文件系统时间戳提供,用户可改系统时间或文件属性。两者都未经服务器背书,也不能防篡改。做唯一键需结合内容哈希等不可变特征;做新鲜度判断应依赖服务端返回的 ETag、Last-Modified 或内容校验,而不是客户端元数据。
- 跨目录可重名,同目录内唯一
- lastModified 可被时钟或文件 API 修改
- 唯一键需内容哈希,新鲜度需服务器认可
元数据的产生与局限
File.name 取自用户选择的本地文件路径的末段,操作系统允许同一目录下文件名唯一,但不同目录或不同来源可重名。例如用户从文件夹A和文件夹B分别选择同名报告.pdf,两个 File 对象的 name 都可能是 report.pdf。File.lastModified 来自文件系统时间戳,单位毫秒,可被文件系统或工具改写,且用户系统时钟不准确时,该值可能偏离真实修改时间。
浏览器不对此提供真实性保证。File 是 Blob 的子类,只负责承载二进制数据和基本元数据,其内容可随意构造:new File([...], 'x', { lastModified: 0 }) 可任意指定 lastModified。因此,将这两个字段组合作为唯一键或新鲜度判据,在重复上传、同名校验、缓存更新等场景中会产生误判。
重复上传判定失灵
假设上传组件以 name + lastModified + size 作 key,用来判断用户是否选择了同一文件。用户先上传 /home/a/photo.jpg,该文件 lastModified 为 1610000000000。之后同一文件被复制到 /home/b/photo.jpg,系统可能保留原修改时间,也可能更新为复制时间。若复制更新为 1611000000000,则内容未变导致哈希相同,但 lastModified 不同使得 key 不同,从而误判为新文件。
更常见的是同名不同内容:用户修改 photo.jpg 并另存为同名文件,lastModified 变为新时间。若用同一 key 则视为新文件,这是合理的。但若用户修改后手动改回原时间,则 key 不变,上传逻辑可能跳过。解决方式是读取文件内容并计算 SHA-1 或 SHA-256 指纹,比较哈希而不是元数据,才能可靠去重。
何时可以信赖或需要降级
在单个页面会话中,如果只希望区分不同 File 对象,name 和 lastModified 可作粗略提示,但绝不能用于持久化存储中的唯一键。当文件来自同一目录且用户未修改系统时间时,lastModified 能近似反映修改顺序,但它不精确:毫秒粒度可能不足以区分快速连续修改。
对新鲜度判断,可靠做法是让服务器返回资源版本信息如 ETag,或在上传前计算内容哈希。前端若坚持使用 lastModified,至少应同时记录 size 并验证服务端记录的 lastModified 是否一致,但攻击者仍可通过伪造时间绕过。最终权衡:若需强一致性,必须引入摘要算法;若只是交互提示,可接受误判但应明确标注。
容易答错的地方
- lastModified 可靠地反映文件最后保存时间
- 错误:lastModified 能可靠反映文件的最后保存时间。实际上,文件被移动或复制时时间可能改变,且用户可改系统时钟。真实修改时间由文件系统记录,不可信。依据:File API 只暴露属性,不保证其与服务器或内容同步。
- name+lastModified+size 组合足够唯一
- 错误:相同大小和名字但不同内容的文件很常见,时间戳也可伪造。哈希冲突概率极低,基于内容才可靠。组合只是降低误判率,并不能根除。
面试官还会怎么问?
那么 File 对象有没有可靠的唯一标识?
没有内建标识。File 对象本身引用一个底层数据块,但不同 File 可共享相同 Blob 数据。要获得唯一标识,需计算内容哈希。但哈希也有碰撞理论上,实际用 SHA-256 已足够安全。
用 lastModified 做缓存新鲜度判断,后端如何配合?
后端可返回 Last-Modified 头,但应同时依赖 ETag 实体标签。前端用内容哈希或 ETag 比较,避免依赖本地时间戳。若本地时钟不准,条件请求可能失效。
如果只是防重复点击上传,不持久化,还需要哈希吗?
不需要。可在上传按钮禁用、或对比 File 对象的 size 和名字简单提示。但若用户选择相同路径文件但内容已变,按钮禁用会阻止重新上传,需要记录 active 状态。哈希开销大但更准确。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。