向Firebase数据库上传文件时返回空对象的问题求助
问题解决:Firebase中存储图片后显示空对象
问题场景
通过Axios将Canvas生成的图片以File对象形式发送到Firebase Realtime Database时,数据库中image字段对应的是空对象,但生成的File对象本身包含正确的文件名、大小、类型等信息。
用户原始代码:
var dataCanvas = canvas.toDataURL().replace("data:image/png;base64,", ""); let file; let config = { headers: { "Content-Type": "multipart/form-data", }, }; const linkSource = `data:image/png;base64,${dataCanvas}`; await fetch(linkSource) .then((res) => res.blob()) .then((blob) => { file = new File([blob], "test", { type: "image/png" }); console.log('file is founded', file); axios.post( "https://DB.firebaseio.com/screens.json", JSON.stringify({ image: JSON.stringify(file) }), config ) .then(function(response) { console.log('response ', response); }) .catch(function(error) { // console.log(error); }); });
核心原因
- File对象无法被JSON序列化:
JSON.stringify(file)仅能序列化对象的可枚举属性,而File/Blob的核心二进制数据不属于可枚举属性,序列化后仅保留空壳结构,最终存入Firebase的就是空对象。 - Realtime Database不支持二进制存储:Firebase Realtime Database是JSON文档型数据库,仅适合存储字符串、数字、数组、JSON对象这类结构化数据,无法直接存储二进制文件。
解决方案
方案1:用Firebase Storage存图片,Realtime Database存访问链接(推荐)
这是Firebase官方推荐的文件存储方案,将二进制文件存在专门的Storage服务中,数据库仅保存文件的下载链接,既节省数据库空间,又方便后续访问。
代码示例(使用Firebase SDK)
// 假设已完成Firebase App初始化 const storage = firebase.storage(); const storageRef = storage.ref('screens/test.png'); // 指定存储路径和文件名 var dataCanvas = canvas.toDataURL().replace("data:image/png;base64,", ""); const linkSource = `data:image/png;base64,${dataCanvas}`; await fetch(linkSource) .then(res => res.blob()) .then(blob => storageRef.put(blob)) // 上传Blob到Storage .then(snapshot => snapshot.ref.getDownloadURL()) // 获取下载链接 .then(downloadURL => { // 将链接存入Realtime Database return axios.post( "https://DB.firebaseio.com/screens.json", { image: downloadURL } ); }) .then(response => console.log('操作成功', response)) .catch(error => console.error('操作失败', error));
代码示例(使用Axios调用REST API)
如果不想引入Firebase SDK,可直接调用Storage的REST接口:
var dataCanvas = canvas.toDataURL().replace("data:image/png;base64,", ""); const linkSource = `data:image/png;base64,${dataCanvas}`; await fetch(linkSource) .then(res => res.blob()) .then(blob => { const formData = new FormData(); formData.append('file', blob, 'test.png'); // 替换为你的Storage Bucket地址,格式:https://firebasestorage.googleapis.com/v0/b/[你的Bucket名]/o/[存储路径] const storageUrl = "https://firebasestorage.googleapis.com/v0/b/your-bucket-name/o/screens%2Ftest.png"; // 上传到Storage return axios.post(storageUrl, formData, { params: { uploadType: 'media' } }); }) .then(storageRes => { // 拼接下载链接 const downloadURL = `https://firebasestorage.googleapis.com/v0/b/your-bucket-name/o/${storageRes.data.name}?alt=media`; // 存入Realtime Database return axios.post("https://DB.firebaseio.com/screens.json", { image: downloadURL }); }) .then(dbRes => console.log('完成', dbRes)) .catch(err => console.error('出错', err));
方案2:直接存储Base64字符串(不推荐)
如果仅需临时存储小体积图片,可跳过File/Blob转换,直接将Canvas生成的Base64字符串存入数据库:
var dataCanvas = canvas.toDataURL().replace("data:image/png;base64,", ""); axios.post( "https://DB.firebaseio.com/screens.json", { image: dataCanvas } ) .then(response => console.log('保存成功', response)) .catch(error => console.error('保存失败', error));
注意:Base64字符串体积比原二进制文件大30%左右,大量存储会占用过多数据库空间,仅适合小图场景。
额外注意
- 确保Firebase Storage的安全规则允许上传和访问(开发阶段可临时设置为公开,生产环境需配置严格的权限规则)。
内容的提问来源于stack exchange,提问作者Ammar Kayali
相关产品推荐
相关产品推荐

