Khi xây dựng file uploader, cần tránh upload file trùng lặp (cùng nội dung). So sánh nội dung file phía client.
Vấn đề
- Tính hash (MD5, SHA-256) toàn bộ file ở client: tốn CPU, chậm với file lớn (>100MB).
- So sánh tên file/kích thước: không tin cậy (file khác nhau có thể trùng tên/size).
Giải pháp thực tế
1. Hash mẫu (Sampling Hash) - Cân bằng tốc độ/độ tin cậy
- Chỉ hash các chunk cố định: ví dụ 1MB đầu, 1MB giữa, 1MB cuối.
- Kết hợp:
hash = hash(first 1MB + last 1MB + size + name). - Rất nhanh, độ trùng lặp dương tính (false positive) rất thấp.
2. Sử dụng Web Worker cho hash toàn bộ
- Đưa việc hash (SparkMD5, crypto.subtle.digest) vào Web Worker để không block UI.
- Hiển thị progress bar khi hash file lớn.
3. Server-side deduplication (tốt nhất)
- Client gửi metadata (name, size, sampling hash) trước.
- Server kiểm tra DB, nếu đã có file giống hệt (so sánh hash đầy đủ server-side), báo "đã tồn tại", client bỏ qua upload.
- Đảm bảo 100% chính xác, giảm tải client.
Ví dụ: Sampling hash nhanh với SparkMD5
async function quickHash(file) {
const spark = new SparkMD5.ArrayBuffer();
const chunkSize = 1024 * 1024; // 1MB
const totalChunks = Math.ceil(file.size / chunkSize);
// Chỉ hash 3 chunk: đầu, giữa, cuối
const indices = [0, Math.floor(totalChunks/2), totalChunks-1].filter((v,i,a)=>a.indexOf(v)===i);
for (const i of indices) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const buffer = await file.slice(start, end).arrayBuffer();
spark.append(buffer);
}
return spark.end() + '-' + file.size; // hash + size làm fingerprint
}
Kết luận: Không có "shortcut" hoàn hảo. Kết hợp sampling hash client-side + full hash server-side là cân bằng tốt nhất.