秒传是前端算哈希与后端查表协作的结果:前端用readAsArrayBuffer()计算字节级哈希,大文件需分块流式哈希;后端必须同时校验hash和size;预检请求须POST JSON而非拼接URL;秒传后需客户端校验一致性并提示用户。

秒传不是浏览器自带功能,而是前端算哈希 + 后端查表的协作结果。只要哈希一致且服务端确认存在同内容文件,就跳过上传直接返回链接——这才是真正“秒”。
用 FileReader.readAsArrayBuffer() 算哈希,别用 readAsText()
哈希必须基于原始字节,否则换行符、BOM、编码转换会让同一文件在不同环境生成不同值。HTML5 中唯一可靠路径是读取 ArrayBuffer:
-
readAsText()会按默认编码解析,破坏二进制一致性,绝对禁用 - 大文件(>500MB)在 Safari 上可能触发内存警告,需分块读取 + 流式哈希(如
spark-md5的hashBinary()) - 服务端校验必须同时比对
hash和size,仅靠哈希有极小碰撞风险,双条件才安全
发起预检请求时,fetch 的 body 必须是 JSON,不能拼 query
很多实现把哈希塞进 URL:/api/upload/check?hash=xxx,这会导致 URL 长度超限(尤其 SHA-256)、缓存干扰、服务端日志污染。正确做法是 POST JSON:
fetch('/api/upload/check', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
hash: 'd41d8cd98f00b204e9800998ecf8427e',
filename: 'report.pdf',
size: 10485760
})
})
注意:字段名(hash/filename/size)必须和服务端约定完全一致,后端通常用这三者联合查库或 Redis。
立即学习“前端免费学习笔记(深入)”;
秒传成功后,别直接跳转,先做客户端一致性校验
服务端返回的 url 或 file_id 是可信的,但用户可能中途修改了文件却没重新触发哈希计算(比如改名后重选)。容易被忽略的点:
- 秒传响应里应带
etag或服务端计算的哈希,前端可比对是否与本地一致 - 如果秒传返回的是 CDN 地址,要确保该地址支持 HEAD 请求,可用
fetch(url, { method: 'HEAD' })检查Content-Length是否匹配原始size - UI 上建议显示“已存在,秒传完成”,而不是静默跳过——用户需要感知这个优化发生了
最常出问题的环节不在哈希计算,而在服务端查表逻辑没覆盖 size 校验,或者前端把 FormData 和秒传预检混用导致 header 冲突。哈希只是起点,双端对齐才是关键。



















