如何在原生JS中使用Fetch API实现BunnyCDN视频上传进度显示
使用Fetch API实现BunnyCDN视频上传进度显示
要在Fetch API下实现BunnyCDN视频上传的进度跟踪,核心思路是通过自定义ReadableStream监控文件数据的发送进度——Fetch本身没有原生的上传进度事件,但文件上传的进度与流的读取进度完全同步,因此可以通过包装文件流来实现进度更新。
以下是修改后的完整代码,已集成进度显示功能:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BunnyCDN 视频上传器</title> </head> <body> <input type="file" id="fileHandler"> <p id="fileName"></p> <progress id="progressBar" max="100" value="0"></progress> </body> <script> const libraryId = 'LIBRARY_ID'; const AccessKey = 'API_KEY'; const fileHandler = document.getElementById('fileHandler'); const fileName = document.getElementById('fileName'); const progressBar = document.getElementById('progressBar'); fileHandler.addEventListener('change', function(e) { const file = e.target.files[0]; if (!file) return; fileName.textContent = file.name; progressBar.value = 0; // 第一步:创建视频元数据,获取GUID const createVideoOptions = { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', AccessKey }, body: JSON.stringify({ title: file.name, }) }; fetch(`https://video.bunnycdn.com/library/${libraryId}/videos`, createVideoOptions) .then(r => r.json()) .then(res => { const guid = res.guid; if (!guid) throw new Error('无法获取视频GUID'); // 第二步:带进度跟踪的文件上传 let uploadedBytes = 0; const totalBytes = file.size; // 自定义ReadableStream,跟踪上传进度 const stream = new ReadableStream({ start(controller) { const reader = file.stream().getReader(); function readChunk() { reader.read().then(({ done, value }) => { if (done) { controller.close(); return; } // 更新已上传字节数和进度条 uploadedBytes += value.length; const progress = Math.round((uploadedBytes / totalBytes) * 100); progressBar.value = progress; controller.enqueue(value); readChunk(); }).catch(err => { controller.error(err); console.error('流读取错误:', err); }); } readChunk(); } }); const uploadOptions = { method: 'PUT', headers: { 'Content-Type': 'application/octet-stream', AccessKey }, body: stream }; return fetch(`https://video.bunnycdn.com/library/${libraryId}/videos/${guid}`, uploadOptions); }) .then(r => { if (r.ok) { progressBar.value = 100; console.log('上传成功'); } else { throw new Error('上传请求失败'); } }) .catch(err => { console.error(err); alert('上传过程中发生错误'); }); }); </script> </html>
关键实现说明
- 自定义ReadableStream:通过包装文件的原生流,在每次读取数据块时累加已发送字节数,计算进度并更新进度条。Fetch会将流中的数据逐步发送至服务器,因此流的读取进度等价于实际上传进度。
- 进度计算:使用
(已上传字节数 / 文件总字节数) * 100得到百分比,确保进度条平滑更新。 - 稳定性优化:添加了文件存在性检查、API返回GUID有效性验证、流读取错误捕获,同时将
innerHTML替换为textContent避免XSS风险。 - 最终状态处理:上传请求成功后强制将进度条设为100%,确保状态统一。
内容的提问来源于stack exchange,提问作者Wraith
相关产品推荐
相关产品推荐

