React大视频上传S3前获取时长时object URL网络活动相关问题
核心原理解释
- 你在Network面板看到的
blob:开头的请求,并不是向外网上传数据,只是浏览器内部访问本地文件的虚拟请求:你通过URL.createObjectURL()为本地File对象生成的blob链接,是浏览器分配的内部资源标识符,仅在当前页面生命周期内有效。当你把这个地址赋值给video元素的src属性时,浏览器的媒体解析引擎需要读取视频的元数据(时长、编码、分辨率等),因此发起了针对该blob地址的内部范围请求,你看到的Content-Range头就是媒体引擎分片读取本地文件内容的标识,所有请求的处理都在本地完成,没有数据被发送到外部服务器。 - 你提到的「正式上传前的等待期网络活动」,如果此时还没触发S3上传逻辑,大概率是两种情况:要么是浏览器预读取文件内容做元数据解析,要么是你的上传逻辑在做前置准备(比如请求S3预签名URL、计算文件哈希校验值、分片切割等),不属于文件上传本身的流程。
进度获取方案
1. 视频元数据解析进度(即你提到的“文件准备中”进度)
因为媒体引擎读取元数据只需要拉取文件开头的极小部分数据,对于绝大多数视频文件来说这个过程都是毫秒级完成的,用户几乎感知不到,不需要单独做进度展示。如果你的业务场景确实需要处理TB级超大视频,要监控解析进度,可以用FileReader的progress事件读取文件内容,手动解析视频头信息,示例代码如下:
const handleChange = (e: ChangeEvent<HTMLInputElement>) => { if (e.target.files && e.target.files.length === 1 && !file) { const selectedFile = e.target.files[0]; setFile(selectedFile); const reader = new FileReader(); // 监听读取进度 reader.onprogress = (event) => { if (event.lengthComputable) { const percent = Math.round((event.loaded / event.total) * 100); // 这里可以把percent存到state给用户展示 } }; // 元数据仅存在于文件开头部分,读取前1MB足够,无需加载整个文件 reader.readAsArrayBuffer(selectedFile.slice(0, 1024 * 1024)); // 原有获取时长的逻辑补充内存释放处理 const vid = document.createElement("video"); const fUrl = URL.createObjectURL(selectedFile); vid.src = fUrl; vid.onloadedmetadata = () => { setDuration(vid.duration); // 用完立刻释放blob URL,避免大文件占用内存 URL.revokeObjectURL(fUrl); vid.remove(); }; } };
2. S3上传进度
这部分是用户能明确感知到的长耗时流程,你可以根据使用的上传方案获取进度:
- 如果用AWS官方JS SDK上传,调用
upload方法时可以监听httpUploadProgress事件直接拿到已上传字节数,计算进度即可 - 如果是自己实现的预签名URL分片上传,每完成一个分片上传就累加已上传大小,除以总文件大小得到进度
注意事项
你当前的实现存在内存泄漏风险:URL.createObjectURL()生成的blob链接会强制持有文件的内存引用,直到页面刷新或者主动调用URL.revokeObjectURL()释放,大视频文件如果不主动释放会占用大量浏览器内存,建议在拿到时长后立即执行释放操作,同时移除临时创建的video元素。
内容的提问来源于stack exchange,提问作者Flo Ragossnig
相关产品推荐
相关产品推荐

