2023-06-11 14:57:47
使用 Fetch API 下载视频文件大小为 0 字节的问题通常由 mode: 'no-cors' 配置或不必要的 Content-Type 请求头引起,可通过移除这些配置并优化请求逻辑解决。
问题根源分析mode: 'no-cors' 的副作用
该模式会使响应变为 opaque(不透明),导致无法通过 response.blob() 或 response.json() 读取内容,最终生成空文件。
浏览器直接访问 URL 时不受此限制,但 Fetch API 的 no-cors 模式会主动屏蔽响应数据。
不必要的 Content-Type 请求头
Content-Type 用于标识 请求体 的数据类型(如 POST 上传文件时),而下载文件时服务器会通过响应头返回正确的类型。
手动设置 Content-Type: 'video/mp4' 可能干扰服务器处理,导致响应异常。
移除 mode: 'no-cors'
使用默认的 cors 模式,确保服务器配置了正确的 CORS 策略(如 Access-Control-Allow-Origin: *)。
若服务器未配置 CORS,请求会直接失败(而非生成空文件),便于调试。
删除不必要的请求头
仅在需要时(如身份验证)添加请求头,避免手动设置 Content-Type。
完整代码示例
response.ok 检查确保仅处理 HTTP 状态码为 200-299 的响应,避免因 404 或 500 错误导致后续操作失败。
response.blob() 的作用将二进制响应体转换为 Blob 对象,适用于视频、图片等文件的处理。
URL.createObjectURL() 与 revokeObjectURL()
创建的 URL 仅在当前文档有效,需在下载完成后释放内存。
忽略释放可能导致内存泄漏,尤其在频繁下载时。
CORS 策略要求若视频托管在跨域服务器上,需确保服务器返回以下响应头:
Access-Control-Allow-Origin: *Access-Control-Allow-Methods: GET如何处理大文件下载?对于超大文件,可使用 ReadableStream 分块读取并写入本地文件(需浏览器支持 Streams API),避免内存溢出。
如何显示下载进度?通过 response.body.getReader() 读取流数据,结合进度条组件更新进度:
const reader = response.body.getReader();let receivedLength = 0;const totalLength = +response.headers.get('Content-Length');while (true) { const { done, value } = await reader.read(); if (done) break; receivedLength += value.length; console.log(`下载进度: ${Math.round((receivedLength / totalLength) * 100)}%`);}为什么浏览器直接访问 URL 能下载,但 Fetch 失败?浏览器直接访问时可能绕过了 CORS 限制(如简单请求),而 Fetch API 默认遵循同源策略,需服务器明确允许跨域。