使用Firebase Storage上传后调用getDownloadURL报storage/object-not-found错误
Firebase Storage上传后调用getDownloadURL偶尔报object-not-found的解决方法
我在用Firebase Storage的uploadBytesResumable接口上传文件,之后调用getDownloadURL获取下载链接时,偶尔会遇到以下错误:
Firebase Storage: Object 'storatge_data/9d668c90-8381-4161-b9f1-d016f9b51837/files/xxx.m4a' does not exist. (storage/object-not-found)
我尝试通过判断字节传输完成来避免提前调用getDownloadURL:
if ((snapshot.bytesTransferred !== snapshot.totalBytes)) { return of(null) }
但问题仍然偶尔出现,我的完整代码如下:
const newUploadFiles = (files: File[], updateDocRef: DocumentReference<DocumentData>) => { const resUpload = [...uploadFilesImage] from(files).pipe( mergeMap((file, i: number) => { const storageRef = ref(storage, `storatge_data/${id}/files/${file.name}`) const uploadTask = uploadBytesResumable(storageRef, file) return fromEventPattern((handler) => uploadTask.on('state_changed', handler) ).pipe( mergeMap((snapshot: any) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 resUpload[i].progress = parseInt(progress.toFixed(0)) setProressFiles((prev) => ([...prev, resUpload[i]])) if ((snapshot.bytesTransferred !== snapshot.totalBytes)) { return of(null) } return from(getDownloadURL(snapshot.ref)).pipe( mergeMap(url => { const type = classifyFile(file.name) let setType: any = of(null) if (type === 'music') { setType = onDrop(file) } return from(setType).pipe( map(fileDetail => ({ file: url, type, fileDetail, hash: "", fileType: file.name.substring(file.name.lastIndexOf('.')), fileName: file.name })) ) }) ) }), takeWhile(data => data === null, true), filter(each => each !== null) ) }), toArray(), concatMap(data => { return from(updateDoc(updateDocRef, { files: data })) }) ).subscribe() }
问题原因
仅通过bytesTransferred === totalBytes判断上传完成并不严谨——即使字节传输完毕,Firebase Storage可能还在进行文件的最终校验、持久化或元数据写入操作,此时文件并未完全就绪,调用getDownloadURL就会触发找不到文件的错误。
正确的做法应该是监听上传任务的**success状态**,这是Firebase官方确认上传完全完成的标志。
修复方案
修改代码,通过snapshot.state判断上传状态,仅在状态为'success'时才执行getDownloadURL逻辑:
const newUploadFiles = (files: File[], updateDocRef: DocumentReference<DocumentData>) => { const resUpload = [...uploadFilesImage] from(files).pipe( mergeMap((file, i: number) => { const storageRef = ref(storage, `storatge_data/${id}/files/${file.name}`) const uploadTask = uploadBytesResumable(storageRef, file) return fromEventPattern((handler) => uploadTask.on('state_changed', handler) ).pipe( mergeMap((snapshot: any) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 resUpload[i].progress = parseInt(progress.toFixed(0)) setProressFiles((prev) => ([...prev, resUpload[i]])) // 仅当上传状态为success时才继续后续逻辑 if (snapshot.state !== 'success') { return of(null) } return from(getDownloadURL(snapshot.ref)).pipe( mergeMap(url => { const type = classifyFile(file.name) let setType: any = of(null) if (type === 'music') { setType = onDrop(file) } return from(setType).pipe( map(fileDetail => ({ file: url, type, fileDetail, hash: "", fileType: file.name.substring(file.name.lastIndexOf('.')), fileName: file.name })) ) }) ) }), takeWhile(data => data === null, true), filter(each => each !== null) ) }), toArray(), concatMap(data => { return from(updateDoc(updateDocRef, { files: data })) }) ).subscribe() }
关键修改点
- 替换判断条件:将
bytesTransferred !== totalBytes改为snapshot.state !== 'success',确保只有上传任务完全完成后才调用getDownloadURL。 - 利用Firebase官方的状态机制,避免依赖字节数这种可能存在延迟的判断逻辑。
内容的提问来源于stack exchange,提问作者Panudeth Jaruwong
相关产品推荐
相关产品推荐

