Firebase Storage对象不存在错误:图片已上传却无法添加至云端
问题解决:Firebase Storage上传成功但无法获取下载URL
错误现象
每次尝试向Firebase添加图片时触发以下错误:
FirebaseError: Firebase Storage: Object 'items/Screenshot at May 22 07-33-37.png9573dc82-ec43-4789-88ec-e93727d6a11f' does not exist. (storage/object-not-found)
图片已成功上传至Firebase Storage,但无法获取下载URL并同步到Firestore。
问题根源
- 存储引用路径错误:创建Storage引用时额外添加了
gs://cart-app-b469e.appspot.com前缀,而ref函数的第二个参数只需传入存储桶的相对路径,带前缀会导致实际存储路径与查询路径不匹配。 - 异步操作顺序混乱:
uploadBytes是异步操作,但代码未等待其完成就直接调用getDownloadURL,此时文件可能还未完成上传,触发"对象不存在"错误。 - 状态逻辑不一致:
newItemImage初始化为空字符串,但判断条件用newItemImage == null,逻辑不匹配。
修复后的完整代码
import React, { useState, useEffect } from 'react'; import { db, storage } from './../../config/config'; import { ref, uploadBytes, getDownloadURL } from 'firebase/storage'; import { getDocs, collection, addDoc } from 'firebase/firestore'; import { ItemsList, AddForm } from './shopStyle'; import { v4 } from 'uuid'; export const Shop = () => { const [items, setItems] = useState([]); const itemsRef = collection(db, "items"); // 新商品状态 const [newItemName, setNewItemName] = useState(""); const [newItemPrice, setNewItemPrice] = useState(0); // 初始化改为null,与文件对象的空状态匹配 const [newItemImage, setNewItemImage] = useState(null); useEffect(() => { const fetchData = async () => { try { const data = await getDocs(itemsRef); const filteredData = data.docs.map((doc) => ({ ...doc.data(), id: doc.id, })); setItems(filteredData); } catch (err) { console.error(err); } }; fetchData(); }, []); function handleImage(e) { let pickedFile; if (e.target.files && e.target.files.length > 0) { pickedFile = e.target.files[0]; setNewItemImage(pickedFile); console.log(pickedFile); } } const addItems = async (e) => { e.preventDefault(); if (!newItemImage) return; // 移除gs://前缀,直接使用存储桶相对路径 const imageRef = ref(storage, `items/${newItemImage.name + v4()}`); try { // 等待上传完成后再执行后续操作 await uploadBytes(imageRef, newItemImage); alert("Image uploaded"); // 上传完成后获取下载URL const downloadURL = await getDownloadURL(imageRef); const newItem = { Image: downloadURL, Name: newItemName, Price: newItemPrice, }; await addDoc(itemsRef, newItem); // 清空输入字段 setNewItemImage(null); setNewItemName(""); setNewItemPrice(0); } catch (err) { console.log(err); } }; return ( <div> <AddForm onSubmit={addItems}> <input accept="image/*" id="icon-button-file" type="file" onChange={handleImage} /> <input type="text" placeholder="name" value={newItemName} onChange={(e) => setNewItemName(e.target.value)} /> <input type="number" placeholder="price" value={newItemPrice} onChange={(e) => setNewItemPrice(e.target.value)} /> <button type="submit">Add</button> </AddForm> <ItemsList> {items.map((item) => ( <div key={item.id}> <img src={item.Image} alt={item.Name} /> <h1>{item.Name}</h1> <h4>{item.Price}</h4> </div> ))} </ItemsList> </div> ); };
核心修复说明
- 路径修正:创建
imageRef时移除gs://前缀,确保引用路径与实际存储路径完全一致。 - 异步等待:使用
await等待uploadBytes完成,保证文件上传成功后再执行获取下载URL的操作。 - 状态逻辑统一:将
newItemImage初始化为null,判断时用!newItemImage,逻辑更严谨。 - 表单优化:将按钮
type设为submit,配合表单的onSubmit事件,避免重复绑定点击事件。
内容的提问来源于stack exchange,提问作者Daniel Bisceanu
相关产品推荐
相关产品推荐

