概述通过 Range 请求按偏移拉取资源,保存进度以支持中断恢复,并对数据进行校验以保障可靠性。断点续传与校验async function sha256(bytes) {
const buf = await crypto.subtle.digest('SHA-256', bytes);
return Array.from(new Uint8Array(buf)).map(x => x.toString(16).padStart(2,'0')).join('');
}
async function downloadWithRange(url, chunkSize = 1024 * 1024) {
let offset = await loadProgress(url);
const parts = [];
while (true) {
const res = await fetch(url, { headers: { Range: `bytes=${offset}-${offset + chunkSize - 1}` } });
if (res.status === 416) break;
if (!res.ok && res.status !== 206) throw new Error('range fetch failed');
const ab = await res.arrayBuffer();
const bytes = new Uint8Array(ab);
parts.push(bytes);
offset += bytes.length;
await saveProgress(url, offset);
if (bytes.length < chunkSize) break;
}
const total = parts.reduce((n, p) => n + p.length, 0);
const out = new Uint8Array(total);
let i = 0;
for (const p of parts) { out.set(p, i); i += p.length; }
const digest = await sha256(out);
return { bytes: out, digest };
}
进度持久化示例function openDB(name) {
return new Promise((resolve, reject) => {
const r = indexedDB.open(name, 1);
r.onupgradeneeded = () => { const db = r.result; if (!db.objectStoreNames.contains('progress')) db.createObjectStore('progress'); };
r.onsuccess = () => resolve(r.result);
r.onerror = () => reject(r.error);
});
}
async function saveProgress(key, value) {
const db = await openDB('range');
const tx = db.transaction('progress', 'readwrite');
tx.objectStore('progress').put(value, key);
await new Promise((resolve, reject) => { tx.oncomplete = resolve; tx.onerror = () => reject(tx.error); });
db.close();
}
async function loadProgress(key) {
const db = await openDB('range');
const tx = db.transaction('progress', 'readonly');
const req = tx.objectStore('progress').get(key);
const val = await new Promise((resolve, reject) => { req.onsuccess = () => resolve(req.result || 0); req.onerror = () => reject(req.error); });
db.close();
return val;
}

发表评论 取消回复