基于AngularFire复制Firebase Storage图片遇CORS跨域问题
我正在为Web应用开发复制功能,用于复制表格数据及其关联图片。目前卡在使用AngularFire复制Firebase Storage中的图片环节:常规图片上传时,我会通过input元素将文件传给AngularFireStorage,示例代码如下:
import { AngularFireStorage } from '@angular/fire/compat/storage'; const file = $event.target.files[0]; const filePath = `${myPath}`; const task = this.storage.upload(filePath, file);
需要复制的图片已作为HTML <img>元素加载在页面上。我是否需要使用Blob对象或其他工具将URL转换为Firebase可上传的格式?
我尝试了以下代码,但出现了CORS错误:
var startFileDuplication = (_this) => { _this.storage .ref(`/tableImages/${this.userInfo.uid}/${this.activeDate}/${activeTable.key}`) .listAll() .subscribe(async (data) => { for (const image of data.items) { const path = image.fullPath; const url = await image.getDownloadURL(); const fileBlob = await this.downloadFile(url); const file = new File([fileBlob], image.name, { type: fileBlob.type }); const newPath = `/tableImages/${_this.userInfo.uid}/${_this.activeDate}/${newTableKey}/${image.name}`; _this.storage.upload(newPath, file); } }) } async downloadFile(url: string): Promise<Blob> { const response = await fetch(url); return await response.blob(); }
错误信息翻译:
从源 'http://localhost:4200' 访问 'https://firebasestorage.googleapis.com/*' 已被CORS策略阻止:请求的资源上不存在 'Access-Control-Allow-Origin' 标头。如果不透明响应能满足你的需求,请将请求的模式设置为 'no-cors' 以在禁用CORS的情况下获取资源。
1. 直接通过Firebase Storage复制文件(最优解)
你当前先下载再上传的做法完全绕路,还触发了CORS问题。Firebase Storage本身支持存储桶内直接复制文件,无需经过前端下载,效率更高且能彻底规避CORS问题。
修改代码使用copyTo方法直接复制:
var startFileDuplication = (_this) => { _this.storage .ref(`/tableImages/${this.userInfo.uid}/${this.activeDate}/${activeTable.key}`) .listAll() .subscribe(async (data) => { for (const image of data.items) { // 构造目标路径 const newPath = `/tableImages/${_this.userInfo.uid}/${_this.activeDate}/${newTableKey}/${image.name}`; // 获取目标文件引用 const targetRef = _this.storage.ref(newPath); // 直接执行复制操作 await image.ref.copyTo(targetRef); } }) }
2. 若必须下载再上传(解决CORS问题)
如果因为特殊限制必须走下载上传流程,需要配置Firebase Storage的CORS规则:
- 本地创建
cors.json文件,内容如下:
[ { "origin": ["http://localhost:4200"], "method": ["GET"], "maxAgeSeconds": 3600 } ]
- 用Firebase CLI执行命令上传规则(替换成你的存储桶名称):
firebase storage:upload cors.json --bucket=你的存储桶名称
另外,可修改downloadFile方法添加no-cors模式(但此模式下Blob无法读取内容,仅适合单纯上传场景):
async downloadFile(url: string): Promise<Blob> { const response = await fetch(url, { mode: 'no-cors' }); return await response.blob(); }
关于URL转上传格式的问题
是的,如果必须通过前端上传,需要将图片URL转换为Blob/File对象,你当前的转换方式是正确的,但前提是解决CORS问题。不过优先推荐用Firebase原生的文件复制API,这是最省心的方案。
内容的提问来源于stack exchange,提问作者Marian07

