现代浏览器可用FileReader与crypto.subtle.digest()前端计算文件SHA-256哈希,需将File转ArrayBuffer后调用digest(),结果转十六进制字符串;大文件应分块处理或使用hash-wasm等库;哈希比对需统一编码格式,其核心用途是去重与一致性校验,而非防篡改。
FileReader + crypto.subtle.digest() 计算文件 SHA-256 哈希现代浏览器(Chrome 80+、Firefox 74+、Edge 79+)原生支持在前端计算文件哈希,无需上传到服务端即可完成校验。核心是组合使用 FileReader 读取二进制数据,再用 crypto.subtle.digest() 计算 SHA-256(或 SHA-1/SHA-512)。注意:digest() 只接受 ArrayBuffer,不能直接传 Blob 或 File。
实操要点:
File 对象需先调用 .arrayBuffer()(推荐)或用 FileReader.readAsArrayBuffer() 获取原始字节localhost 下运行,否则 crypto.subtle 会抛 SecurityError
Uint8Array,需转为十六进制字符串才便于比对async function calculateSHA256(file) {
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// 使用示例
document.querySelector('#file-input').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (file) {
const hash = await calculateSHA256(file);
console.log('SHA-256:', hash); // 如:a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
}
});
file.arrayBuffer() 一次性加载直接调用 file.arrayBuffer() 会将整个文件载入内存,1GB 文件就占 1GB RAM,极易卡死或被浏览器终止。真实场景中应分块读取 + 流式哈希(类似 Node.js 的 crypto.createHash)。但浏览器 Web Crypto API 不支持增量 digest,所以需手动拼接分块哈希 —— 这**不等价于整体哈希**,不可用于校验。
正确做法是:用 File.slice() 分段读取,全部加载进内存后一次性调用 digest();或改用第三方库如 spark-md5(仅支持 MD5)或 hash-wasm(支持 WASM 加速的 SHA-256,可流式)。
关键提醒:
hash-wasm 的 sha256Multi() 支持传入多个 ArrayBuffer,内部按标准方式处理,等效于整文件哈希file.arrayBuffer(),加 loading 提示和 try/catch 防崩溃前端算出的哈希和后端/预存值比对不上?大概率不是算法问题,而是字符串表示不一致。SHA-256 原始结果是 32 字节二进制,转换成字符串时有三种常见变体:
hex(小写十六进制,64 字符):最常用,hash-wasm 和多数服务端默认输出hex(大写):Python hashlib.sha256().hexdigest().upper() 会这样,需统一转小写再比对base64:Node.js createHash('sha256').update(buf).digest('base64') 输出 44 字符,含 +//,前端需用 
atob() 解码后再 digest —— 但更稳妥的是服务端也返回 hex另外注意:
File,而后端收到的可能是经 multipart 解析、重命名、加时间戳后的文件,字节流已不同前端计算哈希**不能替代 HTTPS 传输加密或服务端校验**。它无法防止中间人替换文件内容后再伪造哈希(因哈希本身也走同一通道),也不能防御恶意用户修改本地 JS 绕过计算逻辑。它的实际价值集中在:
真正需要防篡改的场景(如固件升级包),必须由可信源签名(RSA/ECDSA),前端验证签名,而非只验哈希。